Perl

Willemers Informatik-Ecke

UNIX-Handbuch

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.

Interpreter und Skript

Der Interpreter von Perl heißt einfach perl und befindet sich im Verzeichnis /usr/bin. Das ist deswegen so wichtig, weil in einem Perl-Skript angegeben wird, wie der Interpreter heißt. Dazu schreiben Sie in die erste Zeile eines Perl-Skripts:

#!/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.

Variablen

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.

Skalare

Skalare nennt Perl die einfachen Variablen, die sowohl numerische Werte als auch Strings aufnehmen können. Enthält eine Variable eine Zahl, wo eine Zeichenkette erwartet wurde, wandelt Perl diese kurz entschlossen um. Auch umgekehrt wird eine Zeichenkette automatisch in eine Zahl umgewandelt, wenn eine Zahl erwartet wird. Ist der Inhalt nicht als Zahl zu interpretieren, ist ihr Wert eben 0.

Zahlenkonstanten

Zahlenkonstanten können ganze Zahlen oder Fließkommazahlen sein. Zur Darstellung des Dezimalkommas verwendet Perl, wie im englischen Sprachraum üblich, den Punkt. Große Zahlen oder kleine Brüche stellt Perl mit Hilfe des vom Taschenrechner bekannten Buchstaben e dar. Hinter dem e steht der Exponent zur Basis 10, mit dem die Zahl zu multiplizieren ist. Um es einfacher zu sagen: Dort steht die Anzahl der Stellen, um die das Komma nach rechts zu verschieben ist. Die folgenden Zahlen sind alle gleich groß:

1.000000e6
10.00000e5
100.0000e4
1000.000e3
10000.00e2
100000.0e1
10000000
100000000e-1
1000000000e-2

hexadezimal und oktal

Auch hexadezimale und oktale Zahlen können verwendet werden. Mit oktalen Zahlen sind Sie schon einmal beim Befehl
chmod in Berührung gekommen. Eine oktale Zahlendarstellung wird durch eine führende 0 eingeleitet. 010 ist also nicht 10, sondern 8. Die hexadezimale Darstellung beginnt mit 0x. 0x10 ist also 16. Wenn Sie nicht wissen, was hexadezimal oder oktal ist, brauchen Sie sich keine Sorgen zu machen. Dann brauchen Sie auch deren Darstellung nicht. Sie sollten dann lediglich aufpassen, dass Sie keine Zahl mit 0 beginnen lassen.

Tausenderpunkte

Sehr praktisch ist die Möglichkeit, in große Zahlen Unterstriche einzufügen, ohne den Zahlenwert zu verändern. So kann man Unterstriche zur besseren Lesbarkeit an Stelle der im Deutschen üblichen Tausenderpunkte verwenden. Eine Million ist im Quelltext als 1_000_000 leichter zu erkennen als in der normalen Darstellung 1000000.

Zeichenketten

Zeichenkettenkonstanten werden in Anführungszeichen oder Hochkommata eingeschlossen. Der Unterschied zwischen beiden ist, dass innerhalb von Anführungszeichen Variablen ausgewertet werden und bei Hochkommata nicht.

In einer Zeichenkette gibt es für diverse Sonderzeichen spezielle Zeichen, die alle mit einem Backslash beginnen. Ihre Bedeutung ist in der folgenden Tabelle erklärt.

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

Variablennamen

Die Variablennamen von Skalaren werden durch ein $ eingeleitet. Danach muss ein Buchstabe oder ein Unterstrich erscheinen, und anschließend können in beliebiger Folge Buchstaben, Ziffern oder Unterstriche folgen. Ein Variablenname kann maximal 255 Buchstaben lang sein. Mein Tipp: Schöpfen Sie es nicht bis zum Letzten aus. Allerdings sollten Sie sich auch nicht auf zwei oder drei Buchstaben beschränken. Verwenden Sie so viele, dass klar wird, was die Variable enthält. Das folgende Beispiel ist auch für den Uneingeweihten leicht lesbar.

$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;

Strenge Aufsicht

Option -w

Obwohl es ein schönes Gefühl ist, nicht kontrolliert zu werden, führt die mangelnde Kontrolle durch den Interpreter auch leicht zu Flüchtigkeitsfehlern. Der erste Schritt zu sicheren Programmen ist die Verwendung der Option -w hinter dem Interpreteraufruf. Damit wird beispielsweise erreicht, dass eine Variable angemahnt wird, die im Quellcode nur einmal vorkommt. Man kann relativ sicher sein, dass eine solche Variable aufgrund eines Schreibfehlers entstanden ist.

use strict

Ein weiterer Schritt zur Steigerung der Sicherheit wird durch die Anweisung use strict; erreicht. Wenn diese zu Anfang des Skripts gesetzt wird, wird jede Variable darauf geprüft, ob sie vorher deklariert wurde. Eine Variable kann durch Voranstellen des Schlüsselwortes my deklariert werden. Die Einleitung zu dem Beispiel von oben würde dann wie folgt lauten:

#/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.

Operationen auf Skalare

Oben wurde es schon ein wenig vorweggenommen: Die Variablen erhalten ihre Werte durch die Zuweisung. Das zuständige Zeichen ist das Gleichheitszeichen.

$name = "hugo";
$wert = 15;

Numerische Operationen

Sie werden mit numerischen Variablen auch rechnen wollen. Dazu werden die Operatoren verwendet, die sich seit den Zeiten von Fortran inzwischen in fast allen Programmiersprachen durchgesetzt haben. Dabei werden die folgenden Operatoren jeweils zwischen zwei Operanden gestellt, weshalb man sie auch binäre Operatoren nennt.

Punkt vor Strich

Die Priorität der Operatoren steigt in der Tabelle nach unten hin an. Es gilt also die bekannte Punkt-vor-Strich-Regel. Natürlich gibt es auch in Perl Klammern, mit denen man die Regel außer Kraft setzen kann. Zu den wenigen unären Operatoren (Unäre Operatoren sind solche, die nur auf einen Operanden wirken.) gehören die Inkrementierung und die Dekrementierung, die in C mit ++ bzw. -- realisiert werden. Auch diese Operatoren gibt es in Perl. ++ bewirkt, dass der Inhalt der Variablen um 1 erhöht wird, und -- sorgt dafür, dass er um 1 vermindert wird.

Operator Wirkung
+ Addition
- Subtraktion
* Multiplikation
/ Division
% Modulo (Rest einer ganzzahligen Division)
** Potenzierung

Operatoren auf Zeichenketten

Aneinander\-hängen

Durch einen Punkt werden zwei Zeichenketten aneinander gehängt:

$fullname = $firstname . " " . $lastname;

Vervielfältigen

Mit einem x kann ein String vervielfältigt werden. Um das Wort >>huhu<< zu erzeugen, könnten Sie in Perl also schreiben:

$ruf = "hu" x 2;

Ersetzen

Innerhalb einer Zeichenkette können Sie Zeichenketten ersetzen. Das Beispiel zeigt das Ersetzen jedes Auftreten von >>saulus<< durch >>paulus<< in der Variablen $apg:

$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");

Bunt gemischte Elemente

Die Werte innerhalb einer solchen Klammer müssen nicht gleichartig sein. Es können alle Skalare bunt gemischt auftreten. Sie müssen nicht einmal als Konstanten auftreten, es können auch Variablen eingesetzt werden.

Zugriff auf Arrayelemente

Um auf ein Element einer Arrayvariablen zuzugreifen, hängen Sie den Index des referenzierten Elements in eckigen Klammern an die Variable. Der Index beginnt bei 0. Beim Referenzieren wird auf ein Element des Arrays und nicht auf das gesamte Array zugegriffen. Die Elemente eines Arrays sind aber Skalare. Konsequenterweise wird einem Element eines Arrays auch wieder ein $ vorangestellt:

$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];

Zuweisung an mehrere Variablen

Damit enthält das Array @werte den Wert (7, 5, 2). Wenn dieser Vorgang für den Programmierer anderer Sprachen schon ungewöhnlich wirkte, dann wird die Möglichkeit, mit einer Zuweisung Werte in mehrere Variablen zu schieben, zur äußerst praktischen Kuriosität:

($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.

split()

Den umgekehrten Weg gehen Sie mit der nützlichen Funktion split(). Mit ihr können Sie eine Zeichenkette in ein Array aufbrechen. Die Bruchstelle wird durch ein frei wählbares Zeichen festgelegt. Diese Funktion erleichtert beispielsweise die Analyse von CGI-\"Ubergabedaten sehr. Das folgende Beispiel teilt einen Satz an den Stellen in seine Wörter auf, wo ein Leerzeichen steht:

@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";

Dimension

Die Zeichenkombination $# ermittelt den höchsten Index eines Arrays. Dieser Wert ist also um eins geringer als die Dimension des Arrays. Die beiden Zeichen werden dem Namen des Arrays statt des Zeichens @ vorangestellt. Ein leeres Array liefert -1. Im Beispiel oben wird dies als Index für das letzte Element verwendet. Die Dimension eines Arrays kann auch ermittelt werden, indem eine direkte Zuweisung eines Arrays an einen Skalar durchgeführt wird. Da ein Skalar ein Array nicht aufnehmen kann, geht Perl davon aus, dass der Programmierer die Dimension ermitteln will.

Hash

Dieser Variablentyp ist eine Art paarweises Array, wobei das jeweils vordere Element als Zugriffsschlüssel auf das hintere Element wirkt. Man spricht auch von einem assoziativen Array. Beispiel:

%kfz = ('sl', 'Schleswig', 'fl','Flensburg','hh','Hamburg');
$kfz{'hg'} = 'Bad Homburg';
$kfz{'hg'} = 'Hochtaunuskreis';
$key="hg";
print "Schlüssel = $key, Wert = $kfz{$key}\n";

Definition

In der ersten Zeile wird ein Hash namens %kfz definiert. Das sieht ähnlich wie bei der Definition eines Arrays aus. Es fällt auf, dass die Variable ein Prozentzeichen trägt, und die Art der Inhalte lässt vermuten, dass hier je zwei benachbarte Werte immer zusammengehören. Der jeweils erste Wert ist der Schlüssel und der zweite der Inhalt. Der Zugriff auf ein Element des Hashs ähnelt dem Zugriff auf ein Array. Allerdings wird keine Nummer als Index verwendet, sondern der Schlüssel, und statt eckiger Klammern sind es hier geschweifte.

Werte hinzufügen und ändern

In der zweiten Zeile wird dem Hash %kfz noch ein Wert hinzugefügt. Dadurch, dass es den Schlüssel hg noch nicht gibt, gibt es anschließend ein Element mehr. In der dritten Zeile wird wieder der Schlüssel hg verwendet, und darum bleibt die Anzahl der Elemente des Hashs gleich. Da hier ein Schlüssel verwendet wird, den es schon gibt, wird nur der Inhalt dieses Elements verändert.

Zugriff auf Elemente

In der vierten Zeile wird ein Skalar $key mit dem Inhalt >>hg<< gefüllt, damit in der letzten Zeile darüber das entsprechende Hashelement referenziert werden kann. Wie schon beim Array zu beobachten war, wird aus dem % des Hashs ein $, sobald kfz über den Schlüssel dereferenziert wird und damit nur ein Skalar entnommen wird.

Löschen eines Elements

Mit der Funktion delete() können Einträge aus einer Hashvariable wieder gelöscht werden. Dabei wird der Schlüssel als eindeutige Referenz angegeben. Der Aufruf sieht so aus:

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>;

chomp

Das Programm wartet an dieser Stelle auf die Eingabe des Benutzers, die er mit einem Return abschließen muss. Das Zeilenendezeichen steht damit immer am Ende der Zeichenkette. Da dieses in den seltensten Fällen gebraucht wird, verwendet man die Funktion chomp(), um die Zeilentrenner aus einer Zeichenkette zu entfernen. Typischerweise sieht eine Eingabe dann so aus:

$ask = <STDIN>;
chomp $ask;

Aufrufparameter

Wie bei Shellskripten finden sich die Kommandozeilenparameter in vordefinierten Variablen. Allerdings unterscheidet Perl zwischen dem Namen des Skripts und seinen Parametern. Der Name des Skripts befindet sich in $0. Allerdings sind die Aufrufparameter nicht in $1 und folgende abgelegt, sondern befinden sich im vordefinierten Array @ARGV. Der erste Parameter befindet sich in $ARGV[0]! Das folgende Beispiel zeigt die Kommandozeilenparameter des Skriptes an:

#!/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.

Suchen in Zeichenketten

Ob eine bestimmte Zeichenkette in einer Variablen vorkommt, kann ebenfalls als Bedingung verwendet werden. Der Syntax der Suche ist von sed bzw. von vi bekannt:

$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.

Verknüpfung boolescher Ausdrücke

Zum Verknüpfen zweier Vergleiche gibt es die Operatoren and und or. In Anlehnung an die Sprache C können Sie für and auch \\ und für or auch || schreiben. Der Operator and liefert nur dann einen wahren Wert, wenn beide Ausdrücke wahr sind. Der Operator or wird genau dann wahr, wenn mindestens einer der beiden Ausdrücke wahr ist. Anders ausgedrückt ist or nur dann falsch, wenn beide Ausdrücke falsch sind.

if

Die Abfrage if ermöglicht es, auf Bedingungen zu reagieren. Auf das Schlüsselwort if folgt in Klammern die Bedingung. Danach folgen die Befehle, die unter der Bedingung ausgeführt werden sollen, in einem Block, der durch geschweifte Klammern eingeschlossen wird.

if ( $wert > 5 )
{
  print "Mensch, der Wert ist ja über 5!\n";
}

else

Zu dem Befehl if gibt es auch ein else, an das wiederum ein Block von Anweisungen angehängt werden kann. Dieser Block wird dann ausgeführt, wenn die Bedingung falsch ist.

elsif

Mit dem Befehl elsif ist es möglich, auf eine weitere Bedingung zu prüfen. So können Sie beispielsweise einen Block reagieren lassen, wenn die Variable 3 ist, einen anderen, wenn sie 5 ist, und mit einem else alle übrigen Werte abhandeln. Das folgende Beispiel zeigt ein if mit elsif und else. Hier werden Zeichenketten verglichen.

#!/usr/bin/perl -w
$ask = ;
chomp($ask); # wirf den Zeilenvorschub weg!
if ( $ask eq ärnold" )
{
  print "Hallo, Arnold!\n";
}
elsif ($ask eq "willemer" )
{
  print "Hochverehrter Herr Willemer!\n";
}
else
{
  print "Was willst Du denn hier, $ask?\n";
}

Eingabe

Zunächst wird eine Zeichenkette von der Tastatur eingelesen. Da das erst mit der Eingabe der Taste Return beendet ist, befindet sich der Zeilenvorschub am Ende der Zeichenkette in der Variablen $ask. Die Funktion chomp() eliminiert den Zeilenvorschub.

Entscheidung

Es folgt die eigentliche Abfrage if. Zunächst wird geprüft, ob die Eingabe "arnold" lautete. Dann wird Arnold mit Hallo begrüßt. Das elsif heißt so viel wie "andernfalls wenn". Hier wird geprüft, ob "willemer" eingegeben wurde. Dann fällt die Begrüßung gleich sehr viel formeller aus. Das else behandelt alle anderen Fälle.

for

Die Schleife for kommt zum Einsatz, wenn abzählbare Durchläufe einer Schleife gebraucht werden. Perl kennt zwei Formen des for. Da ist einmal die Zählschleife, die hier behandelt wird, und dann die Schleife foreach, mir der sich der nächste Abschnitt befasst.

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

Schleife über eine Liste

Die Schleife foreach ist ein Spezialfall der for-Schleife, die Werte einer Liste durchläuft. Sie ist mit der for-Schleife in Shellskripten vergleichbar. Dem Schlüsselwort foreach folgt als Erstes ein Skalar, der nacheinander alle Werte der darauf folgenden Liste annimmt.

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";
}

keys und sort

Die Schleifenvariable $key nimmt nacheinander die Werte des dahinter stehenden Ausdrucks an. Im Zentrum dieses Ausdrucks steht die Hashvariable %kfz. Die Funktion keys() liefert ein Array mit allen Schlüsselwerten der Hashvariablen. Auf diese wird dann die Funktion sort() angewendet, sodass $key nacheinander die Schlüssel in sortierter Reihenfolge annimmt.

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);

Zerlegen eines Arrays

Die folgende Schleife ist ein Beispiel für das Aufspalten eines Arrays in einzelne Skalare. Die Bedingung ist lediglich das Array. Hier wird die Tatsache genutzt, dass die Umformung eines Arrays in einen Skalar die Anzahl der Elemente ergibt. Sobald das Array also leer ist, wird es 0 zurückgeben. Diese 0 wird von while als falsch interpretiert und führt zum Ende der Schleife.

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.

CGI-Auswertung

Im Zusammenhang mit CGI-Skripten sind immer wieder Strings wie der folgende auszuwerten. Sie enthalten den Inhalt einer Eingabemaske. Das Ziel ist es, die einzelnen Eingaben zu trennen. Die einzelnen Eingaben sind als Zuweisungen dargestellt, also steht links eine Variable, dann ein Gleichheitszeichen und dann der Wert. Die Zuweisungen sind jeweils durch ein \ getrennt.

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;

my $input = "Name=Otto&Adresse=Mein+Weg%0D%0AOrt&Anrede=Frau"; @zuweisungen = split("&", $input); while (@zuweisungen) { ($zeile, @neu) = @zuweisungen; ($key, $wert) = split("=", $zeile); $wert =~ s/\+/ /g; # + durch leer ersetzen! $input{$key} = $wert; @zuweisungen = @neu; } # Ausgabe foreach $key(sort keys(%input)) { print "Key = $key, Value = $input{$key}\n"; }

Funktionen

Eine Funktion wird mit dem Schlüsselwort sub definiert. Darauf folgen der Name der Funktion und in geschweiften Klammern der Block von Befehlen, der ausgeführt wird, wenn die Funktion aufgerufen wird. Eine Funktion kann von einer beliebigen Stelle durch ihren Funktionsnamen aufgerufen werden. Nach Ausführung der Befehle in der Funktion kehrt der Programmablauf zu dem Befehl zurück, der dem Funktionsaufruf folgt.

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.

Parameter

An Funktionen können auch Parameter übergeben werden. Beim Aufruf werden sie einfach hinter dem Funktionsnamen aufgezählt. Vom inneren der Funktion können Sie über das Array @\_ auf die Parameter zugreifen. Das Beispiel linie ist so erweitert worden, dass als Parameter übergeben wird, wie viele Striche für die Linie verwendet werden sollen.

sub linie {
  print '-' x $\_[0] . "\n";
}
 \dots
linie(5);
 \dots
linie 15;

Lokale Variablen

Lokale Variablen können mit Hilfe der Schlüsselwörter local oder my innerhalb der Funktion definiert werden. Mit my definierte Variablen sind nur innerhalb der Funktion bekannt. Auf eine mit local definierte Variable kann auch von einer Funktion zugegriffen werden, die von der aktuellen Funktion aufgerufen wird.

Dateien

Der Umgang mit Dateien besteht einmal aus dem Lesen und Schreiben von Dateien. Darüber hinaus ist es für eine Skriptsprache auch wichtig, dass man Dateien löschen oder umbenennen kann.

Schreiben und Lesen

Öffnen und Schließen

Perl ist eine ideale Sprache, um Texte auszuwerten. Um das nutzen zu können, muss man auf die Dateien, in denen die Texte stehen, zugreifen können. Im ersten Schritt wird eine Datei geöffnet. Dazu dient die Funktion open(). Der erste Parameter ist das Dateihandle (Handle; engl. Handgriff). Ein Handle ist eine Kennung für eine Ressource. Daran erkennt das Betriebssystem, welche Datei gemeint ist. Das Handle wird für alle weiteren Zugriffe auf die Datei gebraucht. Der zweite Parameter ist der Name der Datei, die geöffnet werden soll. Im folgenden Beispiel wird eine Datei geöffnet und gleich wieder geschlossen:

open(HANDLE, $filename) || die "Datei nicht zugreifbar";
close(HANDLE);

Fehlerbehandlung

Das Oder-Zeichen hinter dem Dateinamen bewirkt, dass bei einem Fehlschlag der Funktion open() die dahinter liegende Befehlsfolge abgearbeitet wird. Hier besteht sie aus der Funktion die() (engl. sterben), die das Programm beendet und die als Parameter übergebene Zeichenkette als letzten Gruß auf der Konsole ausgibt.

Lesen

Aus einer Datei liest man mit Hilfe des beim open() ermittelten HANDLE auf die gleiche Weise, wie schon weiter oben von der Standardeingabe gelesen wurde:

$zeile = ;

Schreiben

Die Ausgabe in eine Datei erfolgt analog über die Funktion print(). Als erster Parameter wird ihr das Dateihandle mitgegeben:

print HANDLE $value;

cat als Perl-Skript

Das folgende Skript ist eine Implementation des Kommandos cat in Perl. Wie der Originalbefehl gibt das Skript cat.pl den Inhalt aller ihm als Parameter übergebenen Dateien auf der Standardausgabe aus.

#!/usr/bin/perl -w
use strict;
my $datei;   # der jeweilige Dateiname
my $zeile;   # die Zeile, die aus der Datei gelesen wird.

foreach $datei (@ARGV) { open(HANDLE, $datei) || die "Fehler beim Öffnen $datei\n"; while ($zeile = ) { print $zeile; } close HANDLE; }

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.

Dateiprüfung

Wie bei UNIX-Skripten können Dateien auf Existenz und andere Eigenschaften geprüft werden. Beispielsweise wird mit -f getestet, ob der nachfolgende Name, hier .rhosts, eine Datei bezeichnet.

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`;

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

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:

http://www.perl.com

Und dann gibt es natürlich auch das Buch.
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