KnowHow - Software - Perl

Altlasten

Ältere Snippets von mir:

permalink.de/tino/193

permalink.de/tino/193

Perl Haters Doc

"Darf ich Dich etwas würgen? Ich mußte diesen ganzen Nachmittag in PERL programmieren, und möchte die Erfahrung gerne weitergeben."

Ein kleines Sammelsurium, warum ich Perl nicht mag

Kleiner, aber unfeiner Unterschied:

$count = $string =~ /d+/g;
$count = () = $string =~ /d+/g;
Wer es nicht sieht: Im ersten Fall wird die Aktion im skalaren Kontext schrittweise durchgeführt, d. h. man muss darüber loopen, im zweiten im Listcontext, d. h. der gesamte String wird evaluiert. Einmal wird also nur zurückgegeben, ob das Pattern gefunden wurde, beim Zweiten wie oft es gefunden wurde (die Länge der Liste). Wen verwirrt solch ein unvorhersehbares Verhalten von Grundoperatoren in einer Sprache bitte nicht?

Zitat aus einem Source den ich schrieb:
# "our" is pronounced like the german word "aua", which means OUCH
# I think, this is a very good description about the construct my/local/our

permalink.de/tino/194

permalink.de/tino/194

Perl Quickie

Hier die "Perl Quickies" für Leute wie mich, die so gut wie jede Programmiersprache kennen, aber sich einfach nicht an all die "eigenartigen" (um nicht abartigen zu schreiben) Konstrukte in Perl erinnern oder erinnern wollen.

Ich versuche mich mit weiteren Kommentaren zurückzuhalten.

Man gewöhnt sich schnell daß man ein Konstrukt entweder rückwärts (ganz ohne Klammern) schreiben kann
die "murx" if $var!=5;
oder vorwärts, dann aber mit der { zwingend am Ende der Zeile, weil man sonst nur ein Kommando angeben kann:
if ($var!=5) {
&cleanup;
  die "murx";
}

Man kann es natürlich auch umgehen, indem man das Listenkonstrukt von Perl mißbraucht, aber mit geht darum, lesbaren und verständlichen Code zu produzieren und nicht irgendein unverständlichen Perl-Kauderwelsch.

Ebenso dürfte die Shell-Artige Paramerterübergabe an Funktionen schnell und problemlos erlernt werden.

Perl hat 3 verschiedene scopes:

  • my: deklariert Variablen im aktuellen Scope (lexikalisch), das bedeutet auch außerhalb Funktionen z. B. nicht über Modulgrenzen hinweg.
  • local: ändert den alten Wert einer "globalen" Variable und kopiert ihn zurück wenn der local wieder out-of-scope geht.
  • our: mit dem man Variablen aus anderen Modulen importieren kann (ob "our" etwas mit "AUA, das tut weh" zu tun hat weiß ich nicht).
Der typische Start eines Scripts das eine config-Datei verwendet sieht also so aus:
use strict;
use bytes;
no utf8;
require "config.pl";
our(%conf);

Das "use strict" kann immer empfehlen, es erzwingt daß man Variablen vor ihrer Verwendung deklaratiert, was Fehlern vorbeugt. "use bytes" bewirkt, daß Perl wieder bytes und nicht UTF-8-Zeichen (genauer: ein erweitertes Derivat) zählt. Es kann sehr verwirrend sein, wenn man - wie ich - eigentlich immer von Binärdartenverarbeitung ausgeht und plötzlich ein 10-byte-String durch fehlendes "use bytes" nur noch 4 Zeichen lang sein soll, weil einiges zufällig UTF-8-artig aussieht. Das "no utf8" schaltet dann auch die UTF-8-Verarbeitung vom Sourcecode aus, ich hatte schon öfters ohne dieses Konstrukt das Problem mit Umlauten in Regexps.

Neben "require" gibt es auch "do", mit dem man in eine andere Perl-Datei verzweigen kann. do entspricht weitgehend dem script aus dem Shell.

$ steht für skalare Variablen, @ für Arrays, % für Hashes. Das sind assoziative Arrays die pro Eintrag 2 Werte haben, Key und Value. Man kann das als "key"=>"Value" schreiben oder auch "key","value", wie immer bei Perl gibt es zig verschiendene (..) Varianten ein und dasselbe auszudrücken.

Die "Verdrahtung" dieser Scopes untereinander ist so eigenartig daß ich das noch nicht so ganz begriffen habe, ich verlasse mich lieber auf klarere Aktionen:

scalar(@arr) ist die Anzahl der Elemente eines Arrays, $#arr ist das nicht (was tut eigentlich $arr?).

Listen iteriert man am einfachsten im List-Modus. Dafür ist der Operator grep nicht schlecht. Aber auch die Zuweisung an ein leeres Array
() = (ausdruck)
kann hilfreich sein.

$val = eval { }
ist auch ein extrem "hilfreiches" Konstrukt um das man vermutlich so gut wie nicht herumkommt, weil es "longjmp" bzw. "try/catch" emuliert.
die("text")
bricht den eval ab, läßt $var auf undef
if (defined($var)) ..
und setzt $@ auf "text". return wert liefert den Wert an $var.

$var kann natürlich auch eine Liste sein, wie überall in Perl:
($one,$two,undef,$four)=eval { .. }

Iterieren kann man auch mit foreach variable (Werte). Läßt man die Variable weg, dann wird $_ als Variable verwendet, genau so wie beim while (..), das allerdings eine Spezialität aufweist (aufzuweisen scheint): while kennt undef was z. B. if anscheinend nicht kennt. Resultat ist, daß man mit if manchmal Fehler bekommt bei Ausdrücken die im while keinen Ärger machen (so genau begriffen habe ich das bisher allerdings nicht). Hauptsächlich passiert das, wenn man mit File-Handles in Variablen arbeitet (so, mein Postnuke hat leider den Fehler daß es Spitze Klammern löscht, weshalb ich das Beispiel hier nicht hinschreiben kann).

(Wird fortgeführt oder auch nicht, kommt drauf an ob ich mich noch länger mit Perl rumschlagen muß. Dieser Text ist zu lang, aber es kurz per Verlinkung zu machen fehlt mir die Zeit.)

permalink.de/tino/s50

permalink.de/tino/s50
Perl und HTTPS: Abbschalten vom SSL_verify_mode

Summary on how to switch off SSL_verify_mode: If you have problems connection to an SSL server using perl LWP, try setting the global SSL context as shown in the first snippet before making the https connection. Wenn sich jemand wundert, warum https:// connects mit LWP nicht funktionieren muß er vermutlich folgendes ins PERL-Script einfügen:

use IO::Socket::SSL;
IO::Socket::SSL::context_init({SSL_use_cert=>0,SSL_verify_mode=>0x00});

Der Grund: Perl prüft das Zertifikat defaultmäßig (SSL_verify_mode=>0x01), deshlab funktionieren Self-Signed Certificates meist nicht, weil eben keine Ausgabestelle dieses ausgegeben hat. Dies ist leider ganz ganz supertief in der Perl-Doku versteckt, selbst beim Suchen im Internet (wenn man weiß wonach man sucht) finden sich nur ca. 4 Referenzen auf ähnliche Codestellen. Symptome:

/usr/bin/lwp-request https://20k.de/

meldet

500 Can't connect to 20k.de:443 ()

Folgendes Script
#!/usr/bin/perl
require LWP::UserAgent;
$ua = LWP::UserAgent->new;
$res = $ua->get("https://20k.de/");
die($res->is_success . ' Code=' . $res->code . " " . $res->message . " " . $res->content);

meldet

Code=500 Can't connect to 20k.de:443 ()

Fügt man aber obiges in diese Code ein, dann funzt er wunderbar (und wird schneller!).