Perl ist eine interpretierte Sprache, die unter Unix entwickelt wurde. Zwar gibt es auch Versionen für andere Betriebssysteme, aber die volle Schönheit von Perl ergibt sich nur unter Unix. Unter anderem liegt das daran, daß Perl integrativ wichtige Eigenschaften der Betriebssystemfamilie benutzt.
Wie viele Sprachen teilt sich Perl in die eigentlichen Sprachelemente und in eine Sammlung von nützlichen Funktionen auf. Die Sprachelemente sind schnell gelernt, das Wissen über die Bestandteile der Funktionssammlung ergibt sich mit der Zeit.
Dieser Einführungstext bezieht sich auf Perl unter Unix. Unter anderen Betriebssystemen unterscheidet sich die Ausführung von Perl etwas; lesen Sie dort einfach die Anleitung Ihrer Perl-Version.
Perl ist eine vollständige Programmiersprache, denn sie enthält die drei Grundstrukturen, die dafür benötigt werden:
#!/usr/bin/perlprint "Hallo Welt!\n"; |
Nun starten Sie es mit der Befehlszeile:
perl kr.pl
Hallo Welt
Warum man "#!/usr/bin/perl" in die erste Zeile schreibt? Weil ein Perl-Programm auch automatisch aufgerufen werden kann, zum Beispiel als Skript über eine Webseite. Dann muß klar sein welcher Perl-Interpreter zuständig ist und wo er zu finden ist. Es empfiehlt sich darüberhinaus, den Interpreter stets mit "perl -w" aufzurufen. Das resultiert im Fehlerfalle zu genaueren und ausführlicheren Informationen.
Die Hauptunterscheidung zu anderen Sprachen ist die Benennung der Variablen.
Jedem Variablenbezeichner wird ein Symbol vorangestellt, daß über
die Verwendung der Variable, nicht aber über deren Typ entscheidet.
$ | Skalarer Wert | Die Variable bezeichnet einen einzelnen Wert, zum Beispiel eine Zahl, ein Zeichen oder eine Zeichenkette. |
@ | Feld (array) | Ein Verbund von Werten, die unter einem Namen zusammengefaßt sind und über einen impliziten Index angesprochen werden können. |
% | Hashtabelle | Wie ein Feld, nur wird statt des impliziten Index eine zweite Spalte eingeführt. In der ersten Spalte sind die Schlüssel (keys) enthalten, die zweite Spalte enthält die Werte (values). |
Beispiele für Variablenbezeichner:
$betrag
@teilnehmer %environment |
Skalarer Wert; Zahlen, Zeichen, Zeichenkette
Verbund, Feld, Array Hashfeld |
Dabei ist zu beachten, daß der Präfix ($, @, %) nicht fest mit dem Variablennamen verknüpft ist, sondern eine Zugriffsmethode darstellt. So spricht man durch "@teilnehmer" das gesamte Feld, mit "$teilnehmer [5]" das Element 5 aus dem Feld "teilnehmer" an. Denn ein Element aus einem Feld ist ein skalarer Wert.
Ein weiteres Beispiel:
#!/usr/bin/perl $hubbel=17; $bubbel=23; print "$hubbel + $bubbel = ",$hubbel + $bubbel; |
Ausgabe:
17 + 23 = 40 |
Interessant ist die Ausgabezeile. Wie man leicht bemerkt, ist die Ausgabeanweisung
"print", ähnlich wie in BASIC. Zeichenketten werden in Anführungszeichen
gesetzt. Die Wirkung ist die unter Unix erwartete:
'Alle Zeichen sind Literale, auch Variablen wie $hubbel' | Alle Zeichen behalten ihre Bedeutung als Literale und werden als sie selbst wiedergegeben. |
"Alle Zeichen sind Literale, aber Variablen werden expandiert: $hubbel" | Alle Zeichen bleiben Literale, aber Variablenbezeichner werden durch ihren Inhalt ersetzt. |
Zusätzlich gibt es die unter C bekannten Symbole für Sonderzeichen.
Hier die Liste:
\a | Alarm, Beep |
\e | Escape |
\f | Seitenvorschub, Form Feed |
\n | Neue Zeile, Newline |
\r | Wagenrücklauf, Carriage Return |
\t | Tabulator, Tab |
\ooo | Beliebiges Zeichen im Oktalcode; "ooo" ist eine oktale Zahl |
\xhh | Beliebiges Zeichen im Hexadezimalcode; "hh" ist eine hexdezimale Zahl |
Perlumgebungsvariablen | |
$_ | Implizite Variable, Standard Input (wird benutzt, wenn keine explizite Variable angegeben ist). |
$. | Enthält die letzte Zeilennummer der zuletzt benutzten Eingabedatei |
$[ | Index des ersten Elements eines Feldes oder des ersten Zeichens in einer Teilzeichenkette (nicht mehr verwenden ab Perl 5!) |
$ARGV | Name des der aktuellen Datei aus <ARGV> |
@ARGV | Das Feld aller Kommandozeilenargumente |
%ENV | Das Hashfeld aller Umgebungsparameter |
Spezielle Dateibezeichner | |
STDERR | Unix Standarddatei "stderr", Standardfehlerausgabekanal |
STDIN | Unix Standarddatei "stdin", Standardeingabekanal |
STDOUT | Unix Standarddatei "stdout", Standardausgabekanal |
Arithmetische Operatoren | |
++, -- |
Autoinkrement, Autodekrement |
** |
Exponentiation |
*, /, % |
Multiplikation, Division, Modulo |
+, - |
Addition, Subtraktion |
<<, >> |
Bitshift links, rechts |
Vergleichsoperatoren (numerisch ; Zeichenkette) | |
> ; gt |
Größer als |
>= ; ge |
Größer oder gleich |
< ; lt |
Kleiner als |
<= ; le |
Kleiner oder gleich |
= = ; eq |
Äquivalenz, Gleichheit |
!= ; ne |
Antivalenz, Ungleichheit |
Logikoperatoren (bitweise ; logisch) | |
and, & ; && | AND, Und |
or, | ; || | OR, Oder |
xor, ^ | Bit XOR |
not, ! ; ~ | NOT, Nicht |
Zeichenkettenoperatoren | |
. | Konkatenation, Zusammenfügen |
x | Listenoperator, Wiederholung; druckt eine Reihe von Zeichen (Bsp.: print "-" x 20; druckt 20 mal "-") |
Perl beherrscht auch reguläre Ausdrücke. Wer sie kennt, liebt sie und lese sie in anderen Dokumentationen nach. Wer sie nicht kennt, sollte sie kennenlernen. Und auch auch in diesem Falle sei auf die reichhaltige Literatur verwiesen.
Perl unterscheidet sich allerdings von den "hohen" Sprachen durch seine umgangssprachliche Natur. Es gibt Varianten, die zwar untereinander ähnlich bis identisch sind, aber je nach Geschmack alles formaler oder weniger formal aussehen lassen. Einer der Gründe, warum sich Perl-Programme nicht so leicht auf Anhieb erschließen: Für ein und dasselbe Problem gibt es manchmal mehrere syntaktische Varianten.
$x = 23;
$a [5] = 12; $s = "Sesam öffne Dich!"; print $x; print "Hello World!\n"; $i = <stdin>; |
Das letzte Beispiel ist eine Eingabeanweisung, die das Setzen des Wertes der Variablen $i über die Tastatur erlaubt. Wie man leicht sehen kann, werden in Perl einfach Unixeigenschaften übernommen. Dem erfahrenen Unixanwender fallen deswegen bestimmte Ansätze in Perl leichter als Benutzern anderer Betriebssysteme.
if AUSDR
unless AUSDR while AUSDR until AUSDR foreach AUSDR |
wenn...dann...
solange...führe aus... während...führe aus... (abweisend) bis...führe aus... (abweisend) für jedes element...führe aus... |
do {
... } until AUSDR; |
Führe den Teil in {..} solange aus, bis AUSDR "wahr" ergibt. (nicht abweisend) |
#!/usr/bin/perl # Berechnung eines Schaltjahres. Ohne Eingabe $jahr = 1997; $ist_schaltjahr = ($jahr % 4 == 0) && ($jahr % 100 != 0) || ($jahr % 400 == 0); print $jahr, ": "; if (! $ist_schaltjahr) { print "Kein "; } print "Schaltjahr\n" |
Ausgabe: $ perl sj.pl 1997: Kein Schaltjahr |
Der logische Ausdruck sollte stets geklammert werden. Es ist zwar nicht immer nötig, aber es ist nicht falsch und Klammerungen erhöhen die Lesbarkeit eines Programms.
Die vollständige Syntax der bedingten Verzweigung sieht so aus
(Teile in "[...]" sind optional)
:
if (logischer_ausdruck)
{ block } [ [ elsif (logischer_ausdruck) { block }] else { block } ] |
Dabei muß der logische Ausdruck stets in geschweifte Klammern "{...}" gesetzt werden, anders als bei Sprachen wie C oder Java, in denen man die Klammern weglassen kann, wenn der Block nur aus einer einzelnen Anweisung besteht.
#!/usr/bin/perl print "Zaehlschleife...\n"; $n = "Hubbel "; for ($i = 1; $i <=3 ; $i++) |
Ausgabe:
Zaehlschleife... 1. mal Hubbel 2. mal Hubbel 3. mal Hubbel |
Der Schleifenkopf einer "for"-Schleife besteht im Steuerteil aus drei Teilen:
(Einführen der Laufvariablen und Setzen des Startwertes ; Abbruchbedingung ; Inkrement/Dekrement)
$i = 1 | Eingeführt wird die Laufvariable $i. Die Zuweisung setzt den Startwert der Schleife auf den Wert 1. |
$i <=3 | Dies ist die Ende-/Abbruchbedingung. Wird der Wert der Wert 3 überschritten, so endet die Schleife. |
$i++ | Inkrement, Zählschritt +1 |
C-Programmierer erkennen die typische Formulierung des Inkrements. Die Zeichenkette "++" bedeutet ein implizites Inkrement. Natürlich bedeutet dann "--" das implizite Dekrement.
In allen Programmiersprachen gibt es eine eiserne Regel:
Die Laufvariable einer Schleife darf niemals innerhalb des Schleifenblocks explizit verändert werden. Das ergibt - je nach Compiler oder Interpreter - undefiniertes Verhalten. |
Auch wenn es Ihre Programmierumgebung zuläßt, lassen Sie es! Es ist nicht cool, unlesbare Programme zu schreiben.
Perl untertützt einige weitere Varianten von Zählschleifen,
zum Beispiel das Abarbeiten von kleinen, bekannten Listen. Alle folgenden
Beispiel führen dasselbe aus, die Ausgabe aller ganzen Zahlen von
1 bis 5:
for ((1,2,3,4,5)) { print $_."\n" } |
foreach ((1,2,3,4,5)) { print $_."\n" } |
foreach (1..5) { print $_."\n" } |
foreach $nr (1..5) { print $nr."\n" } |
#!/usr/local/bin/perl -w $i = 0; while($i < 5) { print "$i\n"; $i++; } |
Ausgabe:
0 1 2 3 4 |
#!/usr/local/bin/perl -w $i = 0; until($i == 5) { print "$i\n"; $i++; } |
Ausgabe:
0 1 2 3 4 |
Zu beachten sind bei der negierten "until"-Version, daß das Rechnen mit logischen Ausdrücken nicht intuitiv möglich ist. Wenn Sie damit keine Erfahrung haben, beschäftigen Sie sich bitte erst damit. Stichwort ist zum Beispiel "DeMorganschen Regeln".
print "Eingabeende mit -q-\n"; do { print "Eingabe: "; $i = <stdin>; chomp ($i); } until ($i eq "q"); print "Geschafft!\n"; |
Ausgabe:
Eingabeende mit -q- Eingabe: a Eingabe: b Eingabe: q Geschafft! |
Damit sind alle Strukturen vorhanden, die zum Programmieren benötigt werden. Perl unterstützt Unterprogramme im alten Sinne (leider keine Funktionen oder Prozeduren, was hier sehr bedauert wird...). Am Ende des Dokumentes wird darauf eingegangen.
Funktion | Erklärung | Rückgabewert/-typ |
Mathematische Funtkionen | ||
abs (r) | Absolutwert von r | Zahl |
atan2 (r1,r2) | Arcustangens von r1/r2 (zwischen -pi und +pi) | Zahl |
cos (r) | Cosinus von r (im Bogenmaß) | Zahl |
exp (r) | Exponentialfunktion | Zahl |
log (r) | Natürlicher Logarithmus von r | Zahl |
sin (r) | Sinusfunktion von r (im Bogenmaß) | Zahl |
sqrt (r) | Quadratwurzel aus r | Zahl |
Zeichenkettenfunktionen | ||
chop (s) | Hiermit wird das letzte Zeichen von s entfernt | Zeichenkette |
chomp (s) | Abschneiden des Eingabetrennzeichens in s | Zeichenkette |
length (s) | Länge von s | Zahl |
join(s0,s1,s2,...,sx) | Verkettung; die Zeichenketten s1 bis sx werden konkatiniert (zusammengefügt), wobei als verbindendes Element stets Zeichenkette s0 dazwischengesetzt wird. | Zeichenkette |
split(s1,s2) | Spaltung; Eine Zeichenkette s2 wird an einer bestimmten Stelle, die durch das Zeichen s1 spezifiziert ist, aufgetrennt. Dabei dürfen für s1 reguläre Ausdrücke benutzt werden. | Liste von Zeichenketten |
index (s1,s2,[n]) | Positionierung; Eine Teilzeichenkette s2 wird in s1 gesucht. Wird sie gefunden, wird die Position zurückgegeben, wenn nicht, ist der Rückgabewert -1. Optional kann der Startpunkt der Suche durch den numerischen Ausdruck $n definiert werden. | Zahl |
substr (s1,n1[,n2[,s2]]) | Extrahieren, Ersetzen; eine Zeichenkette mit der Länge n2 wird aus s1 extrahiert. Ist n1 negativ, so beginnt die Zählung am Ende von s1 und zählt nach links. Ist n1 positiv, so wird von dieser Stelle gezählt, Zählrichtung rechts. Fehlt n1, so wird die gesamte Zeichenkette zurückgegeben. s2 kann die ermittelte Teilzeichenkette ersetzen. | Zeichenkette |
Sonderfunktionen | ||
die s | Brich Ausführung mit Meldung s und einem exit-Code ungleich 0 ab. | |
warn s | Gib Warnmeldung s aus. |
Mit Ausnahme von atan2 ( ) dürfen alle mathematischen Funktionen auch ohne explizites Argument benutzt werden; es wird dann statt dessen der Wert von $_ eingesetzt. Im Folgenden sollen einige Funktionen in einem gemeinsamen Beispiel vorgeführt werden.
Das Beispiel arbeitet eine Zeichenkette ab, die von einem Webclient an einen Webserver geschickt wurde, den sogenannten query string. In diesem Beispiel soll es spezielle Sonderbedingungen geben, um es nicht zu schwierig zu machen. Ein querystring besteht aus einer Liste von Paaren "variable=value", die durch "&" getrennt werden. Beispiel:
q=hubbel+bubbel&kl=XX&pg=q&Translate=on
suchbegriff=Hans+Dampf
$input = $ENV{QUERY_STRING}; ($var,$val) = split("=",$input); $plus = index ($val,"+"); if ($plus >= 0) { substr ($such,index ($such,"+"),1," "); } |
|
$input | suchbegriff=Hans+Dampf |
$var | suchbegriff |
$val | Hans+Dampf |
substr (...) | --> "Hans Dampf" |
Interessanterweise kann man in Perl in einer Zuweisung mehrere Variablen mit Werten belegen. Wenn der Ausdruck rechts von "=" eine Liste ist, dann darf links von "=" eine Liste von Variablen stehen, die einen entsprechenden Typ aufweisen und in entsprechender Anzahl vorhanden sein müssen. Die betreffende Zeile im Beispiel ist fett hervorgehoben.
Um mit Dateien umgehen zu können, werden wie üblich "file handler", Dateibezeichner verwendet. Diese Bezeichner sind der interne Zeiger auf die Dateien und werden mit dem Plattendateinamen zu Beginn der Dateiarbeit verknüpft.
Das Öffnen einer Datei geschieht mit der "open"-Anweisung, die
auch über die Art des Zugangs entscheidet. Das Symbol ">" öffnet
zum Schreiben (Neuanlegen), das Symbol ">>" (Schreiben, ahängen) hängt
Daten an eine bestehende Datei an. Die Symbole werden unmittelbar dem Plattendateinamen
vorangestellt.
open (DATA,">>" . $filename); | öffnet eine Datei, deren Name in der Variablen $filename steht, zum Schreiben und Anhängen. Dateibezeichner ist DATA. |
print DATA "Blubber\n"; | Gibt die Zeichenkette "Blubber\n" in die Datei DATA aus |
close (DATA); | Schließt de Datei DATA |
while (<DATA>) { .. } | Liest aus der Datei DATA zeilenweise (Diamantenoperator) |
Hier ein Beispiel, das eine Datei zum Schreiben öffnet, schließt,
zum Lesen öffnet und die Daten ausgibt (der Operator "my" in der for-Schleife
erzeugt eine lokale Variable; dazu mehr am Ende des Dokuments):
$filename = "datafile.dat"; open (DATA,">" . $filename); for (my $i = 1; $i <= 5; $i++) { print DATA $i."-line\n"; } close (DATA); open (DATA,$filename) || warn "File open error\n"; while (<DATA>) { print "$_"; } close (DATA); |
Ausgabe:
1 2 3 4 5 |
Das Deklarieren eines Unterprogramms erfolgt mit dem Wort "sub", gefolgt
vom Unterprogrammnamen. Es gibt noch andere Möglichkeiten, aber die
hier soll für unsere Zwecke ausreichen. Der Zugriff auf Unterprogramme
wird durch den Aufruf des Namens des Unterprogramms, dem ein "&" vorangestellt
wird, durchgeführt.
sub swap { my $h = $a; $a = $b; $b = $h; } $a=<STDIN>; chop ($a); $b=<STDIN>; chop ($b); print "Vor Aufruf: a=",$a," b=",$b,"\n"; &swap ($a,$b); print "Nach Aufruf: a=",$a," b=",$b,"\n"; |
Eingabe:
2 3 Ausgabe: Vor Aufruf: a=2 b=3 Nach Aufruf: a=3 b=2 |
Im Beispiel geschieht keine ordentliche Parameterübergabe. Es werden einfach globale Variablen manipuliert, Seiteneffekte garantiert. Also schlechter Stil. Alle Argumente werden dem Unterprogramm über das Feld "@_" übergeben, allerdings als lineare Liste (flat list of scalars). Will man (Hash-)Felder übergeben, so ergeben sich Probleme. Dies ist allerdings nicht Aufgabe dieses Textes. Lesen Sie in der weiterführenden Literatur nach, wie man dann vorgeht.
Vielen Dank an Thomas Treffehn (treffehn@brochier.de) für Hinweise auf Fehler in diesem Dokument.