Perl |
Das Buch zur Website! Jetzt bestellen!
|
Larry Wall hat 1987 die Sprache Perl entwickelt, um die Administration von UNIX-Maschinen zu vereinfachen. Perl hat inzwischen Karriere im Internet gemacht, da es auf dem Gebiet der Auswertung von Texten kaum noch zu schlagen ist.
Perl ist eine Interpretersprache, die umfangreiche Möglichkeiten im Umgang mit Texten und Mustern bietet und dabei dennoch eine systemnahe Programmierung ermöglicht. Die Sprache wurde von Larry Wall als Hilfsmittel zur Administration geschaffen und als freie Software unter die GNU General Public Licence gestellt. In der Administration ist Perl inzwischen ein gängiges Werkzeug. Im Bereich der CGI-Skripten ist Perl durch seine Fähigkeiten, mit Texten umzugehen fast konkurrenzlos. Da es den Interpreter inzwischen auf beinahe jeder Plattform gibt, ist Perl ein ideales Tool, um portable Abläufe zu programmieren. Mit Perl können die UNIX-Systemaufrufe erreicht werden, man kann mit Tk grafisch bedienbare Programme schreiben und über entsprechende Schnittstellen auf Datenbanken zugreifen.
Der Syntax ist an C, die Shellskripten und die bekannten UNIX-Tools angelehnt.
#!/usr/bin/perl -w |
Etwas ungewöhnlich ist die Option -w. Sie zeigt alle Warnungen in ausführlicher Form an. Die Dokumentation weist ausdrücklich darauf hin, diese Option zu verwenden.
Anschließend wird die Datei mit Hilfe des Befehls chmod ausführbar gemacht. Danach kann das Skript direkt von der Kommandozeile aus aufgerufen werden.
Alternativ kann ein Skript natürlich auch direkt als Parameter für den Interpreter aufgerufen werden.
perl -w skript.pl |
Als Endung für die Skripten verwendet man traditionell .pl, das ist allerdings keineswegs zwingend. Insbesondere bei CGI-Skripten geht es den Anwender nichts an, in welcher Sprache sie realisiert sind. Und dort ist es eher üblich, dass man die Endung weglässt.
Wie unter UNIX üblich, unterscheidet Perl genau zwischen Groß- und Kleinschreibung.
Perl besitzt wie alle Programmiersprachen Variablen. Allerdings sind deren
Typen etwas ungewöhnlich. Aber gerade das ist der Grund, warum Perl so extrem
leistungsfähig ist. Um die verschiedenen Variablentypen zu unterscheiden,
wird jeder Variablen ein Sonderzeichen vorangestellt.
Variablen
1.000000e6 10.00000e5 100.0000e4 1000.000e3 10000.00e2 100000.0e1 10000000 100000000e-1 1000000000e-2 |
| Symbol | Wirkung |
|---|---|
| \n | Line Feed |
| \t | Tabzeichen |
| \$ | Dollarzeichen |
| \\ | Backslash-Zeichen |
| \l | Nächstes Zeichen in Kleinbuchstaben umwandeln |
| \L .. \E | Zeichen zwischen \L und \E in Kleinbuchstaben umwandeln |
| \u | Nächstes Zeichen in Großbuchstaben umwandeln |
| \U .. \E | Zeichen zwischen \U und \E in Großbuchstaben umwandeln |
$rechnungsbetrag = $stunden * $stundensatz; $mwstbetrag = $rechnungsbetrag * $mwstsatz; |
Dagegen werden Sie die folgenden zwei Zeilen vermutlich bereits in einem halben Jahr selbst nicht mehr verstehen, ohne sich enorm zu konzentrieren. Da Sie sich schon genug auf das Programmieren konzentrieren müssen, sollten Sie es sich ersparen, auch noch über die Bedeutung der Variablennamen nachgrübeln zu müssen.
$rgb = $std * $ss; $mb = $rgb * $ms; |
#/usr/bin/perl -w use strict; my $rechnungsbetrag; my $stunden; my $stundensatz; my $mwstsatz; my $mwstbetrag; |
Der Mehraufwand, die Variablen ganz zu Anfang alle zu nennen, könnte den einen oder anderen Programmierer vielleicht sogar dazu verführen, hinter die Variable einen Kommentar zu schreiben, wozu die Variable gebraucht wird. Das würde wiederum denjenigen glücklich machen, der das Programm später warten muss. Und derjenige, der das Programm später warten muss, könnte im schlimmsten Fall der Autor selbst sein.
$name = "hugo"; $wert = 15; |
| Operator | Wirkung |
|---|---|
| + | Addition |
| - | Subtraktion |
| * | Multiplikation |
| / | Division |
| % | Modulo (Rest einer ganzzahligen Division) |
| ** | Potenzierung |
$fullname = $firstname . " " . $lastname; |
$ruf = "hu" x 2; |
$apg =~ s/saulus/paulus/g; |
Die Syntax scheint vertraut. Tatsächlich entspricht der Befehl dem, was man von vi und sed kennt. Das g am Ende bewirkt das Ersetzen aller Vorkommen. Wird es weggelassen, wird nur das erste Auftreten ersetzt. Die Suchzeichenkette ist ein regulärer Ausdruck. Steht hinter dem g noch ein i, wird die Groß- und Kleinschreibung ignoriert.
Perl besitzt eine große Menge an Möglichkeiten, mit Texten umzugehen.
Sie entfalten sich vor allem im Zusammenhang mit dem Array und dem Hash.
Arrays
Ein Array ist eine Folge von Skalaren. Wird ein Array als Konstante
dargestellt, sind es einfach Werte, die durch Kommata voneinander getrennt
werden und von einer runden Klammer umgeben sind. Der Name einer
Arrayvariablen, die eine solche Liste aufnimmt, wird mit dem Zeichen @
eingeleitet.
my @primzahlen = (1,2,3,5,7,11,13,17,19);
my @namensliste = ("Karl", "Friedrich", "Hans");
|
$wert = $primzahlen[4]; |
In diesem Fall wird das fünfte Element, also die 7, in die Variable $wert kopiert. Es ist nicht das vierte Element, da die Indizes bei 0 beginnen. Perl kann aber auch mehrere Elemente eines Arrays in ein anderes Array kopieren. In diesem Fall werden die einzelnen Indizes in der eckigen Klammer in der gewünschten Reihenfolge aufgezählt und durch Kommata getrennt:
@werte = @primzahlen[4,3,1]; |
($erst, $zweit, @neuprimzahlen) = @primzahlen; |
Hier wird das erste Element des Arrays @primzahlen der Skalarvariablen $erst, das zweite der Skalarvariablen $zweit und der Rest des Arrays @primzahlen dem Array @neuprimzahlen zugewiesen. Das heißt, dass dem Array @neuprimzahlen die Werte 1 und 2 fehlen und dass es ansonsten die restlichen Werte von @primzahlen hat.
@wort = split(/ /, $satz); |
Der erste Parameter ist das Leerzeichen, das durch beliebige Zeichen eingeschlossen werden kann. Üblicherweise verwendet man Anführungszeichen oder Schrägstriche. $wort[0] hat anschließend das erste Wort von $satz, $wort[1] das zweite und so weiter.
Eine kleine Spielerei soll als Beispiel dienen. Mit der Funktion split() wird ein Name an der Stelle, wo sich Leerzeichen befinden, aufgespalten. Das erste Element ist dann der Vorname, und das zweite ist der Nachname.
#!/usr/bin/perl -w $ask = <STDIN>; chomp($ask); # wirf den Zeilenvorschub weg! @name = split(/ /, $ask); print $name[0]."\n"; print $name[1]."\n"; |
Da es Menschen gibt, die mehr als einen Vornamen besitzen, ist die Ermittlung des Nachnamens nicht besonders zuverlässig. An sich brauchen wir nicht das zweite, sondern das letzte Element des Arrays. Hier folgt die Änderung für die letzte Zeile:
print $name[$#name]."\n"; |
%kfz = ('sl', 'Schleswig', 'fl','Flensburg','hh','Hamburg');
$kfz{'hg'} = 'Bad Homburg';
$kfz{'hg'} = 'Hochtaunuskreis';
$key="hg";
print "Schlüssel = $key, Wert = $kfz{$key}\n";
|
delete $kfz('hh');
|
Damit wird der Eintrag mit dem Hamburger Kennzeichen aus dem Hash %kfz gelöscht.
Interaktiv
Perl-Skripten nehmen Eingaben von der Standardeingabe entgegen, indem sie
auf <STDIN> zugreifen, und können mit der Funktion print() auf die
Standardausgabe
ausgeben. Die Aufrufparameter finden Sie im Array @ARGV, und der Zugriff auf
die Umgebungsvariablen erfolgt über die Hashvariable %ENV.
Ein- und Ausgabe
Ausgabe
Die Bildschirmausgaben erfolgen über die Funktion print(). Die Funktion
gibt ihre Parameter auf der Standardausgabe aus. print() hängt
keinen Zeilenvorschub an die Ausgabe an. Soll am Ende der Zeile ein
Zeilenwechsel erfolgen, muss die Zeichenfolge ''\n'' mit einem Punkt
an den Ausgabeparameter gehängt werden. Der Punkt ist der Operator, um zwei
Zeichenketten zu verbinden.
Eingabe
Die Eingabe von Zeilen erfolgt durch die Zuweisung der Standardeingabe an
einen Skalar:
$ask = <STDIN>; |
$ask = <STDIN>; chomp $ask; |
#!/usr/bin/perl print "Skript name: ", $0, "\n"; print "Parameterzahl: ", $#ARGV, "\n"; print $ARGV[0], "\n"; print $ARGV[1], "\n"; print $ARGV[2], "\n"; |
Die Kombination $# liefert den höchsten Index des Arrays. Bei einem Parameter ist also $#ARGV gleich 0! Im Beispiel für den Aufruf des Skripts werden einmal zu viele und einmal gar keine Parameter übergeben:
gaston> argv.pl sonstwas und dann noch dies skript name: ./argv.pl Parameterzahl: 4 sonstwas und dann gaston> argv.pl skript name: ./argv.pl Parameterzahl: -1 gaston> |
Im letzten Fall entstehen drei Leerzeilen, weil ARGV keinen Inhalt hat.
Im Zusammenhang mit for wird später das Skript noch einmal verbessert,
damit es auf die variable Anzahl von Parametern reagiert.
Umgebungsvariablen
Für den Zugriff auf die Umgebungsvariablen gibt es die vordefinierte
Hashvariable %ENV.
Als Schlüssel wird der Name der Umgebungsvariablen verwendet. Dadurch
wird der Zugriff durch einfache Zuweisung erreicht. Um den Inhalt
der Umgebungsvariablen PRINTER zu ermitteln, verwenden Sie einfach
$ENV{PRINTER}:
print $ENV{PRINTER};
|
Um einen neuen Wert für die Umgebungsvariable PRINTER zu setzen, wird ihr einfach ein neuer Wert zugewiesen:
$ENV{PRINTER}="laser";
|
Ablaufsteuerung
Wie in anderen Programmiersprachen auch ist es in Perl möglich, bestimmte
Programmteile nur unter Bedingungen auszuführen oder sie zu wiederholen, bis
eine Bedingung eintritt. Da die Bedingung immer im Zentrum steht, soll
sie zuerst untersucht werden.
Bedingungen
Eine Bedingung kann wahr oder falsch sein. Sie entsteht durch den Vergleich
einer Variablen mit einer anderen Variablen oder einer Konstanten. Solche
Konstruktionen nennt man auch boolesche Ausdrücke. Zum Vergleich von
Zahlenwerten gibt es die folgenden Vergleichsoperatoren.
| Operator | Bedeutung |
|---|---|
| == | gleich |
| != | ungleich |
| < | kleiner |
| <= | kleiner oder gleich |
| > | größer |
| >= | größer oder gleich |
| <=> | Vergleich. Siehe unten |
Der Vergleich <=> fällt etwas heraus, da er keinen booleschen Wert zurückgibt. Er liefert 0, wenn beide Werte gleich sind. Er liefert 1, wenn der linke Wert größer als der rechte ist, und -1, wenn der rechte Wert größer als der linke ist.
Für den Vergleich zweier Zeichenketten gibt es die folgenden Operatoren.
| Operator} | Bedeutung |
|---|---|
| eq | Sind die Strings gleich? |
| ne | Sind die Strings ungleich? |
| lt | Ist der erste String kleiner? |
| le | Ist der erste String kleiner oder gleich? |
| gt | Ist der erste String größer? |
| ge | Ist der erste String größer oder gleich? |
| cmp | Wie strcmp in C: liefert -1 bei kleiner, 0 bei gleich und 1 bei größer |
Auch der Vergleich cmp liefert keinen booleschen Wert, sondern eine Zahl.
$a =~ /suchmich/i |
Dieser Ausdruck ist wahr, wenn in der Variablen $a die Zeichenkette >>suchmich<< vorkommt. Das i hinter dem zweiten Schrägstrich bewirkt, dass bei der Suche nicht zwischen Groß- und Kleinschreibung unterschieden wird. Zwischen den Schrägstrichen können auch reguläre Ausdrücke stehen.
if ( $wert > 5 )
{
print "Mensch, der Wert ist ja über 5!\n";
}
|
#!/usr/bin/perl -w $ask = |
for ($i=0 ; $i<10 ; $i++ )
{
print "$i\n";
}
|
In der Klammer hinter dem for stehen drei Anweisungen, die je durch ein Semikolon getrennt werden. Als Erstes erscheint die Startanweisung. Sie wird einmal vor dem Beginn der Schleife ausgeführt. In diesem Fall setzt sie den Inhalt des Skalars $i auf 0. Die zweite Anweisung ist die Schleifenbedingung. Sie wird vor jedem Durchlauf der Schleife überprüft. Trifft sie nicht mehr zu, wird die Schleife beendet. Der dritte Teil wird nach jedem Durchlauf am Ende des Schleifenblocks durchgeführt. Im Beispiel steht hier die Anweisung, den Skalar hochzuzählen.
Das folgende Beispiel zeigt alle Aufrufparameter des Perl-Skripts an.
#!/usr/bin/perl
print ßkript name: ", $0, "\n";
print "Parameterzahl: ", $#ARGV, "\n";
print "Parameterliste: \n";
for ($i=0; $i<=$#ARGV; $i++)
{
print "$i.: ", $ARGV[$i], "\n";
}
|
Die Kombination $# liefert den höchsten Index des Arrays. Ist das Array leer, ist dieser Wert -1. Bei einem Parameter ist $#ARGV gleich 0! Aus diesem Grund läuft $i in der Schleife auch bis <= $#ARGV. Für den C-Programmierer etwas gewöhnungsbedürftig ist, dass $i auch innerhalb des Strings ausgewertet wird. Hier sehen Sie ein Beispiel für den Aufruf des Skripts:
gaston> argv.pl sonstwas und dann noch dies skript name: ./argv.pl Parameterzahl: 4 Parameterliste: 0.: sonstwas 1.: und 2.: dann 3.: noch 4.: dies gaston> argv.pl skript name: ./argv.pl Parameterzahl: -1 Parameterliste: gaston> |
foreach $i (@array) {
print $i."\n";
}
|
Hier nimmt der Skalar $i nacheinander die Werte des Arrays @array an. In jedem Durchlauf wird also ein Element von @array angezeigt. Das folgende Beispiel wertet wieder die Aufrufparameter aus. Hier sehen Sie, wie foreach die Schleife erheblich vereinfacht:
#!/usr/bin/perl
print "Parameterliste: \n";
for ($i (@ARGV)
{
print "$i \n";
}
|
Nun soll eine Hashvariable ausgewertet werden. Sie soll in der alphabetischen Reihenfolge ihrer Schlüssel angezeigt werden:
%kfz = ('sl', 'Schleswig', 'fl','Flensburg','hh','Hamburg');
$kfz{'hg'} = 'Bad Homburg';
foreach $key (sort keys(%kfz)) {
print "Key = $key, Value = $kfz{$key}\n";
}
|
Statt dem Schlüsselwort foreach kann auch for verwendet
werden. Allerdings erhöht die Verwendung von foreach an solchen
Stellen die Lesbarkeit.
Sonstige Schleifen: while und until
Perl kennt für Schleifen die Schlüsselwörter while und until.
Beim while bleibt das Programm innerhalb der Schleife, sofern die
Bedingung erfüllt ist. Bei until wird die Schleife verlassen, sobald die
Bedingung erfüllt ist. Das eine ist also die Negation des anderen. Beide
Schlüsselwörter können am Anfang oder am Ende der Schleife stehen, je nachdem, wo
die Bedingung abgefragt werden soll. Steht die Bedingung am Ende, wird die
Schleife in jedem Fall einmal durchlaufen. In diesem Fall eröffnet das
Schlüsselwort do die Schleife.
$i = 0;
while ($i<3) {
print "$i\n";
$i++;
}
|
Die Bedingung wird zu Beginn geprüft. Trifft sie zu Beginn nicht zu, wird die Schleife nicht durchlaufen.
$i = 0;
do {
print "$i\n";
$i++;
} while ($i<3);
|
Da hier die Bedingung am Ende geprüft wird, wird die Schleife einmal durchlaufen, auch wenn die Bedingung bereits zu Anfang nicht zutrifft.
$i = 0;
until ($i>=3) {
print "$i\n";
$i++;
}
|
Im Gegensatz zur ersten while-Schleife wird hier die negierte Abfrage geprüft. Im Grunde ist das die gleiche Schleife wie die erste, die mit while erstellt wurde. Die Negierung einer Bedingung ist im Allgemeinen aber schlechter lesbar als die Verwendung von until statt while.
Zu guter Letzt sehen Sie noch die vierte mögliche Variante. Hier wird ebenfalls die Schleife mindestens einmal durchlaufen, bevor die Bedingung geprüft wird.
$i = 0;
do {
print "$i\n";
$i++;
} until ($i>=3);
|
while (@array) {
($a, $b, @neu) = @array;
print $a." ".$b."\n";
@array = @neu;
}
|
Im Innern der Schleife wird das Array durch die Zuweisung jeweils in zwei Skalare und ein neues Array aufgespalten. Die Skalare werden paarweise ausgegeben, und das Restarray wird dem Original zugewiesen.
Name=Willemer&Adresse=Ihre+Adresse%0D%0AOrt&Anrede=Frau |
Das Skript soll die Zeichenkette aufbrechen, und in einem Hash ablegen und den Hash ausgeben. Statt der Ausgabe würde man in der Praxis die Werte in eine Datenbank stellen oder zu einer Datenbankabfrage umformen.
#!/usr/bin/perl -w use strict; my %input; my $zeile; my $key; my $wert; my @zuweisungen; my @neu; |
sub linie {
print '-' x 79 . "\n;
}
\dots
linie;
\dots
linie;
|
Funktionen haben den Vorteil, dass Programmzeilen nicht an verschiedenen Stellen des Programms wiederholt werden müssen. Das Vermeiden von Wiederholungen sorgt für weniger Fehlerquellen. Fehlerkorrekturen in Funktionen, die häufiger aufgerufen werden, lassen mehrere Stellen des Programms davon profitieren. Daneben sorgen Funktionen für Übersicht. Da Details in den Funktionen verborgen werden, entsteht ein Blick auf die Struktur des Gesamtprogramms.
sub linie {
print '-' x $\_[0] . "\n";
}
\dots
linie(5);
\dots
linie 15;
|
open(HANDLE, $filename) || die "Datei nicht zugreifbar"; close(HANDLE); |
$zeile = |
print HANDLE $value; |
#!/usr/bin/perl -w use strict; my $datei; # der jeweilige Dateiname my $zeile; # die Zeile, die aus der Datei gelesen wird. |
Die äußere foreach-Schleife durchläuft das Parameterarray @ARGV.
Jeder der Parameter wird mit open() geöffnet. Dann durchläuft das
Programm die innere
Schleife, in der jede Zeile in den Skalar $zeile eingelesen wird und
dann per print() auf die Standardausgabe gegeben wird. Die Schleife bricht ab,
wenn die Variable zeile nicht mehr zu füllen ist. Nach dem Ende der Schleife wird
die Datei geschlossen, und die foreach-Schleife übernimmt den
nächsten Parameter.
Umgang mit Dateien
Dateioperationen
Perl verfügt über einige Funktionen zur Behandlung von Dateien.
Diese sind an die UNIX-Systemaufrufe angelehnt.
| Befehl | Wirkung |
|---|---|
| unlink $filename | Löschen einer Datei |
| rename $filename,$neuname | \"Andern des Namens einer Datei |
| mkdir $filename | Erzeugen eines Verzeichnisses |
| rmdir $filename | Löschen eines Verzeichnisses |
Weitere Funktionen finden Sie auf der Manpage namens perlfunc.
if ( -f '.rhosts' ) {
unlink '.rhosts';
}
|
Die wichtigsten unären Operatoren:
| Flag | Bedeutung |
|---|---|
| -r -w -x | Vom effektiven UID/GID les-, schreib- bzw. ausführbar |
| -R -W -X | Vom realen UID/GID les-, schreib- bzw. ausführbar |
| -f | Existiert als Datei |
| -d | Existiert als Verzeichnis |
| -l | Existiert als symbolischer Link |
Perl und UNIX
Perl entstand unter UNIX. So nutzt Perl viele Möglichkeiten, die UNIX ihm
bietet. Inzwischen ist Perl auf beinahe jeder Plattform verfügbar.
Wer die Möglichkeit nutzen will, seine Perl-Skripten auch auf anderen Systemen
zu verwenden, sollte UNIX-Besonderheiten in seinen Skripten vermeiden.
Aber für den Systemadministrator, der sich ein paar Hilfsroutinen schreiben will, ist die Nähe von Perl zu UNIX ungeheuer praktisch. Dass solche Skripten
dann nicht portabel sind, wird ihn weniger interessieren.
Aufruf von UNIX-Programmen
Perl kennt auch die Verwendung von Backquotes. Damit können UNIX"=Programme
aufgerufen werden und ihre Ausgabe im Programm weiterverarbeitet werden.
Ein einfaches Beispiel ist die Ermittlung des aktuellen Datums:
$datum = `date +%D`; print "$datum\n"; |
Der Befehl date wird aufgerufen, und seine Ausgabe an die Standardausgabe wird in den Skalar $datum umgeleitet. Die einschließenden Striche sind keine Apostrophe, sondern das Zeichen, das dieselbe Richtung hat wie der Backslash. Aus diesem Grund wird das Zeichen auch Backquote genannt. Die Funktion print() liefert das Ergebnis auf dem Bildschirm.
Das Gleiche funktioniert auch, wenn die Ausgabe des Befehls mehrere Zeilen umfasst. Sie müssen dessen Ausgabe allerdings in einem Array speichern. Als Beispiel wird hier der Befehl ls verwendet:
@dir = `ls`; |
Mit dem Programmpaket Perl wird unter UNIX normalerweise eine umfangreiche
Dokumentation in Form von Manpages installiert. Beim Aufruf von
man perl bekommen Sie in erster Linie eine Übersicht über diese
Manpages und was sie beinhalten.
Eine wichtige Informationsquelle im Internet ist die Webseite:
Und dann gibt es natürlich auch das Buch.
UNIX-Systemprogrammierung
Unter Perl stehen die meisten UNIX-Systemaufrufe, die später im Buch behandelt
werden, zur Verfügung. Selbst Aufrufe wie fork() und kill() sind möglich.
Die Verwendung von Sockets ist durchaus gängige Praxis. Da auch
Netzwerkfunktionen wie accept() oder connect() verfügbar sind, ist es
möglich, Netzwerkserver und Clients zu programmieren.
Informationsquellen
Andrew L. Johnson: Einstieg in Perl
Diese Seite basiert auf Inhalten aus dem Buch
Arnold Willemer: Wie werde ich UNIX-Guru
Verlagsrechte bei galileo computing
| Homepage |
(C) Copyright 2002 Arnold Willemer
|