




Mit Hilfe von Bedingungen und Schleifen steuern Sie die Ausführung von Anweisungsblöcken in Perl-Skripten. Ohne solche Strukturen würde Ihr Perl-Skript einfach von oben nach unten durchlaufen und nacheinander alle Anweisungen abarbeiten, bis es zu Ende ist. Sie könnten nicht überprüfen, ob etwas einen bestimmten Wert hat, und dann gegebenenfalls zu einem anderen Teil des Codes abzweigen, Sie könnten nicht festlegen, ob und wie oft ein Anweisungsblock noch einmal ausgeführt wird - ohne Kontrollstrukturen wäre Perl sehr langweilig.
In dieser Lektion behandeln wir die verschiedenen Bedingungs- und Schleifenkonstrukte, die Sie für Ihre Perl-Skripts brauchen. Unsere heutigen Themen sind:
if, if...else, if...elsif und unless...
   
 while, do...while und until
   
 for und foreach
   
 next, last, redo und Labels
   
 $_ als Abkürzung für viele Operationen
   
 <> aus Dateien lesen
   
  Bedingungen und Schleifen werden manchmal auch komplexe Anweisungen 
genannt, und zwar deshalb, weil Bedingungen und Schleifen im Vergleich zu 
einzelnen Anweisungen, die mit einem Semikolon enden (wie zum Beispiel $x = 5; 
oder $array[0] = "erstes";), wie soll ich sagen ... eben komplexer sind. Der 
wahrscheinlich bedeutendste Unterschied zwischen einfachen und komplexen 
Anweisungen ist allerdings, dass letztere mit ganzen Blöcken von Perl-Code arbeiten.
  Ein Block ist einfach eine in geschweifte Klammern {} gesetzte Folge von beliebigen 
Perl-Anweisungen. Innerhalb eines Blocks können einfache Anweisungen oder andere 
Blöcke stehen, also alles, was auch außerhalb des Blocks auftauchen kann. Wie 
Anweisungen in einem Skript werden die Anweisungen in einem Block nacheinander 
ausgeführt. Zum Beispiel:
while (Bedingung) { # Beginn des Blocks
   Anweisung;
   Anweisung;
   if (Bedingung) { # Beginn des if-Blocks 
      Anweisung;
   }                          # Ende des if-Blocks
   # ... weitere Anweisungen
}                             # Ende des Blocks
Eine andere Eigenschaft von Blöcken ist, dass Perl hinter der letzten Anweisung im Block nicht unbedingt ein Semikolon verlangt. Es ist aber eine gute Idee, das Semikolon trotzdem zu setzen - dann müssen Sie nicht mehr darauf achten, wenn Sie später weitere Anweisungen hinzufügen.
Blöcke, die nicht an eine Bedingung oder Schleife gebunden sind, werden bare blocks oder freistehende Blöcke genannt und nur einmal ausgeführt. Bare blocks können durchaus nützlich sein, besonders wenn Sie sie mit einem Label versehen, doch jetzt werden wir uns erst einmal auf die Blöcke konzentrieren, die zu komplexen Anweisungen gehören.
Mit Hilfe von Bedingungsanweisungen können Sie festlegen, welche Blöcke Perl ausführen soll, wenn ein Ausdruck einen bestimmten Wert hat. Sie setzen eine Bedingung auf, und Perl überprüft, ob diese Bedingung erfüllt ist, das heißt, ob der Bedingungsausdruck wahr ist. Wenn der Ausdruck wahr ist, führt Perl den direkt folgenden Block aus, wenn er falsch ist, überspringt Perl diesen Block und macht beim nächsten Block oder Teil des Skripts weiter. Anders als bei Schleifen wird jeder Block nur einmal ausgeführt.
  Die häufigste Formen der Bedingung sind if (wenn) und seine Varianten if...else 
(wenn...sonst) und if...elsif (wenn...sonst wenn). Die if-Anweisung sieht wie 
folgt aus:
if ( Bedingungsausdruck) {
   # Anweisungen
}
  Bedingungsausdruck kann jeder beliebige Ausdruck sein; er wird in Booleschem 
skalaren Kontext auf seinen Wahrheitswert überprüft. Sie erinnern sich, dass alles 
außer "", 0 und undef als wahr angesehen wird. Ist der Bedingungsausdruck wahr, 
wird der Anweisungsblock ausgeführt. Ist er falsch, passiert gar nichts, und Perl macht 
mit der nächsten Anweisung unter dem if-Block weiter.
  Beachten Sie, dass anders als in C oder Java auf die Bedingung (auch bei else und 
elsif) immer ein Block folgen muss, auch wenn er nur eine einzige Anweisung 
enthält. Sie müssen die geschweiften Klammern immer setzen - aber nicht unbedingt 
in verschiedenen Zeilen, wie ich es eben gezeigt habe. Wo die Klammern stehen, 
bleibt Ihrem Geschmack überlassen.
  Um einen alternativen Block ausführen zu lassen, wenn die Bedingung nicht erfüllt ist, 
verwenden Sie if...else:
if ( Bedingungsausdruck ) {
   # Anweisungen, die ausgefuehrt werden, 
   # wenn Bedingungsausdruck wahr ist
} else {
   # Anweisungen, die ausgefuehrt werden, 
   # wenn Bedingungsausdruck falsch ist
}
  Wie in anderen Sprachen auch, können Sie if und else auch ineinander 
verschachteln:
if ( Bedingungsausdruck 1 ) {
   # Anweisung 1
} else { 
   if ( Bedingungsausdruck 2 ) {
      # Anweisung 2
   } else { 
      if ( Bedingungsausdruck 3 ) {
         # Anweisung 3
      } else { 
         # und so weiter...
      }
   }
}
  Um Ihnen etwas Tipparbeit zu ersparen oder unübersichtlich viele Einzüge zu 
vermeiden, bietet Perl eine dritte Form von if-Bedingungen, das elsif, das diese Art 
von Operationen um einiges kompakter macht:
if ( Bedingungsausdruck 1 ) {
   # Anweisung 1
} elsif ( Bedingungsausdruck 2 ) {
   # Anweisung 2
} elsif ( Bedingungsausdruck 3 ) {
   # Anweisung 3
} else (
   # Anweisung fuer alle anderen Faelle
}
  Beachten Sie, dass sobald die Bedingung eines elsif wahr ist, alle noch folgenden 
elsif-Blöcke übersprungen, das heißt nicht einmal ausgewertet werden. Bei 
verschachtelten if...else-Anweisungen ist es ebenso: In jeder Folge von Blöcken 
wird jeweils nur der erste ausgeführt, dessen Bedingung erfüllt ist.
  Was ist mit Fallunterscheidungskonstrukten wie switch oder case? Perl hat von sich 
aus keine Anweisung für switch (das ist wahrscheinlich das einzige Konstrukt, für das 
andere Sprachen eine eigene Anweisung haben, Perl aber nicht). Allerdings gibt es 
verschiedene Möglichkeiten, mit vorhandenen Perl-Konstrukten eine switch-
Anweisung zu »simulieren«. Ein paar davon werden wir im Abschnitt »Vertiefung« am 
Ende dieser Lektion durchgehen.
  Die unless-Anweisung ist eine Art umgekehrtes if. Manchmal soll eine Operation 
nur ausgeführt werden, wenn eine Bedingung nicht erfüllt ist - was bedeutet, dass in 
einer normalen if...else-Anweisung all das gute Zeug in den else-Teil wandern 
würde wie hier:
if ( Bedingungsausdruck ) {
   # mache nichts
} else {
   # mache das hier
}
  Das ist nicht unbedingt die optimale Lösung. Sie könnten natürlich den 
Bedingungsausdruck negieren (mit not oder !):
if (not Bedingungsausdruck ) {   
   # mache das hier
}
  So müßten Sie es in anderen Sprachen machen und Ihre Denkweise an die Syntax 
anpassen. Perl aber zieht es vor, wenn Sie so denken, wie Sie zu denken gewohnt 
sind, und bietet Ihnen deshalb eine Alternative. Wenn Sie denken: »Mache das und 
das, außer unter dieser Bedingung«, also eine Operation nur ausführen möchten, 
wenn diese Bedingung nicht erfüllt ist, nehmen Sie einfach unless (vom Englischen 
unless, wenn nicht oder außer wenn):
unless ( Bedingungsausdruck ) {
   # mache das hier
}
  Mit diesem unless wird der Block nur dann ausgeführt, wenn der 
Bedingungsausdruck falsch ist. Ist er aber wahr, wird der Block übersprungen. Sie 
können einem unless auch ein else hinzufügen, wenn Sie möchten (aber kein elsif, 
und so etwas wie elsunless gibt es zum Glück auch nicht).
  Manche Bedingungen sind so kurz, dass es viel zuviel Aufwand wäre, all diese 
Klammern und Worte auf sie zu verschwenden. Manchmal ist es sinnvoll, eine 
Bedingung in einen anderen Ausdruck zu betten (was mit if oder unless nicht 
möglich ist, weil diese keine Werte zurückliefern). Verwenden Sie in solchen 
Situationen den Bedingungsoperator ?...:.... Wie bei if...else brauchen Sie einen 
Bedingungsausdruck und zwei Angaben - was Perl bei erfüllter und bei nicht erfüllter 
Bedingung tun soll. Das Ganze schreiben Sie dann in folgender Form:
Bedingungsausdruck ? wert_wenn_wahr : wert_wenn_falsch;
  Hier wird der Bedingungsausdruck auf seine Wahrheit überprüft, genau wie bei if, 
und wenn er wahr ist, dann wird der Ausdruck wert_wenn_wahr ausgewertet (und der 
Wert zurückgegeben), anderenfalls wird wert_wenn_falsch ausgewertet und 
zurückgegeben. Anders als bei if und unless sind wert_wenn_wahr und 
wert_wenn_falsch einzelne Ausdrücke, keine Blöcke. Zum Beispiel können Sie mit 
der folgenden Zeile ganz schnell den höheren von zwei Werten herausfinden:
$max = $x > $y ? $x : $y;
  Dieser Ausdruck sieht nach, ob der Wert von $x größer ist als der von $y. Wenn ja, 
gibt er $x zurück. Wenn $x kleiner oder gleich $y ist, gibt er $y zurück. Der 
zurückgegebene Wert wird dann der Variablen $max zugewiesen. Mit if und else 
würde der gleiche Vorgang so aussehen:
if ($x > $y) {
   $max = $x;
} else {
   $max = $y;
}

Der Bedingungsoperator wird manchmal auch triadischer Operator genannt, weil er drei Operanden hat (monadische Operatoren haben einen, dyadische zwei und triadische drei Operanden).
  Am Tag 2 habe ich Ihnen Perls logische Operatoren &&, ||, and und or erklärt und 
kurz erwähnt, dass Sie damit Bedingungsanweisungen konstruieren können. Lassen 
Sie uns diese Operatoren hier noch einmal betrachten, damit Sie ein Gefühl dafür 
bekommen, wie sie arbeiten. Nehmen Sie den folgenden Ausdruck:
$wert = $dies || $das;
  Um zu verstehen, wie dieser Ausdruck funktioniert, müssen Sie sich an zwei 
Eigenschaften von logischen Operatoren erinnern: dass sie »kurzschließen« und dass 
sie den Wert des zuletzt ausgewerteten Ausdrucks zurückgeben. So wird in dem 
obigen Beispiel zuerst $dies, der linke Operand von ||, überprüft, und dann gibt es 
drei Möglichkeiten:
$dies irgendeinen anderen Wert als 0 oder "" hat, ist der Ausdruck wahr. 
Weil der ||-Operator kurzschließt, wird $das gar nicht mehr ausgewertet. Der 
Operator gibt das Ergebnis der letzten Auswertung zurück - den Wert von $dies, 
der dann der Variablen $wert zugewiesen wird.
   
 $dies den Wert 0 oder  "", ist der Ausdruck falsch. Perl wertet dann $das 
aus. Wenn $das wahr ist, ist der gesamte Ausdruck wahr, und der Operator gibt 
den zuletzt ermittelten Wert zurück - $wert erhält den Wert von $das.
   
 $dies und $das, falsch sind, gibt der Operator falsch zurück, 
und $wert erhält einen 0- oder ""-Wert.
   
  Mit if...else könnten Sie diese Anweisung wie folgt schreiben:
if ($dies) { $wert = $dies; }
else {$wert = $das; }
Mit dem Bedingungsoperator könnten Sie schreiben:
$wert = $dies ? $dies : $das
Aber beide brauchen mehr Platz und sind schwieriger zu begreifen - zumindest schwieriger als der logische Ausdruck, der sich fast wie Klartext liest: dies oder das. Und schon sind Sie fertig.
Wie ich am Tag 2 schon erwähnt habe, werden Ihnen solche für eine Entscheidung eingesetzten logischen Operatoren am häufigsten beim Öffnen von Dateien begegnen:
open(DATEI, "Dateiname") or die "Kann Datei nicht oeffnen\n";
  Wenn die Funktion open eine Datei erfolgreich geöffnet hat, gibt sie wahr zurück, und 
deswegen wird der Teil nach dem or übersprungen, die Funktion die (»stirb«) also gar 
nicht erst ausgeführt. Mehr hierzu am Tag 15.
  Mit den verschiedenen if-Anweisungen in Perl steuert man den Programmfluß, 
indem man (je nachdem, ob eine Bedingung erfüllt ist oder nicht) zu verschiedenen 
Teilen des Skripts abzweigt. Die zweite Steuerungsmöglichkeit sind Schleifen - die ein 
und denselben Anweisungsblock immer wieder ausführen und erst dann aufhören, 
wenn eine bestimmte Bedingung erfüllt ist. Perl hat zwei generelle Arten von 
Schleifen, die beide ungefähr dasselbe machen: while-Schleifen laufen solange, bis 
eine Bedingung erfüllt ist, bei for-Schleifen ist die Anzahl der Durchläufe von Anfang 
an festgelegt. Man kann jede while-Schleife auch als for-Schleife formulieren und 
umgekehrt, doch paßt je nach Situation meist die eine besser als die andere.
  Wir beginnen mit den while-Schleifen. Davon hat Perl drei verschiedene: while, 
do...while und until.
  Die Grundform einer Schleife in Perl ist die while-Schleife mit einem 
Bedingungsausdruck und einem Anweisungsblock:
while ( Bedingungsausdruck ) {
   # zu wiederholende Anweisungen
}
  In der while-Schleife wird der Bedingungsausdruck ausgewertet, und wenn er wahr 
ist, werden die Anweisungen im Block ausgeführt. Danach wird der 
Bedingungsausdruck wieder ausgewertet, und wenn er immer noch wahr ist, wird der 
Anweisungsblock wieder ausgeführt. Dieser Vorgang wiederholt sich so lange, bis der 
Bedingungsausdruck falsch ergibt. Als Beispiel zeige ich Ihnen noch einmal die while-
Schleife aus dem Krümelmonster-Skript, das Sie bereits am ersten Tag gesehen 
haben:
while ( $kekse ne "KEKSE") {
   print 'ich will KEKSE: ';
   chomp($kekse = <STDIN>);
}
  Hier wiederholt sich der Eingabevorgang (die print- und die <STDIN>-Anweisung) so 
lange, bis die Eingabe den String "KEKSE" enthält. Sie könnten diese 
Schleifenanweisung auch so lesen: »Solange der Wert von $kekse nicht gleich dem 
String "KEKSE" ist, tue folgendes.«
  Hier ein anderes Beispiel von Tag 4, das mit einer temporären Variablen $i für den 
Array-Index ein Array durchläuft:
$i = 0;
while ($i <= $#array) {
print $array[$i++], "\n";
}
  In diesem Fall ist die Bedingung, dass $i kleiner oder gleich dem größten Array-Index 
ist. Innerhalb des Schleifenblocks geben wir das aktuelle Array-Element aus und 
inkrementieren $i. So bestimmen wir, wie oft die Schleife durchlaufen werden soll: 
solange wie $i kleiner oder gleich dem größten Index in @array ist, also $#array + 1, 
(weil wir ja bei 0 anfangen).
  Beachten Sie beim Schreiben von while-Schleifen, dass innerhalb der Schleife etwas 
passieren muss, dass sie näher an ihr Ende bringt. Wenn Sie hier zum Beispiel 
vergessen, $i zu erhöhen, wird die Schleifenbedingung nie erfüllt, und die Schleife 
läuft und läuft und läuft ohne Ende.
  Schleifen, die nicht enden, werden Endlosschleifen genannt und können - wenn man 
sie bewußt verwendet - durchaus von Nutzen sein. Zum Beispiel ist eine while-
Schleife ohne Bedingung eine absichtlich endlose Schleife. Sie haben ein paar davon 
in den bisherigen Beispielen gesehen. Diese hier ist aus den Statistikskripten:
while () {
   print 'Bitte eine Zahl eingeben: ';
   chomp ($input = <STDIN>);
   if ($input ne '') {
      $zahlen[$count] = $input;
      $count++;
      $sum += $input;
   }
  else { last; }
}
  Diese Schleife liest bei jedem Durchlauf eine Zeile von der Standardeingabe und kann 
niemals aufgrund einer Schleifenbedingung enden, da es keine Bedingung gibt. Doch 
innerhalb der Schleife überprüfen wir die Eingabe mit if...else. Wenn $input ein 
leerer String ist, unsere if-Bedingung also nicht erfüllt ist, wird der else-Block 
ausgeführt, der nur aus dem Schleifensteuerbefehl last besteht. Dieses last bricht die 
Schleife ab und geht zum nächsten Teil des Skripts weiter. Es gibt in Perl drei solcher 
Schleifensteuerbefehle: last, next und redo, die wir später in diesem Kapitel, im 
Abschnitt »Schleifen steuern«, genauer betrachten werden.
  Ich hätte diese Schleife auch so schreiben können, dass das while eine richtige 
Bedingung hätte und zum richtigen Zeitpunkt abbrechen würde. In diesem speziellen 
Beispiel fand ich es aber einfacher, die Schleife eben auf diese Art zu konstruieren. 
Perl zwingt Ihnen auch bei Schleifen oder Bedingungen kein bestimmtes Denkmuster 
auf, Sie können Ihr Skript so bauen, wie Sie es für die jeweilige Aufgabe am besten 
halten.
  Genau wie unless das Gegenteil von if ist, ist until das Gegenteil von while. Until 
sieht genauso aus wie while, mit einem Bedingungsausdruck und einem Block:
until ( Bedingungsausdruck ) {
   #  Anweisungen
}
  Der einzige Unterschied ist die Bedeutung der Bedingung - mit while wird die 
Schleife so lange durchlaufen, wie die der Bedingungsausdruck wahr ist. Mit until 
wird sie so lange ausgeführt, wie der Bedingungsausdruck falsch ist. Until ist englisch 
und heißt bis - »Bis diese Bedingung wahr ist, tue das hier.«
  Die dritte Form von while-Schleifen ist do. Bei while und until wird die 
Schleifenbedingung ausgewertet, bevor der Block ausgeführt wird - wenn der 
Bedingungsausdruck also von Anfang an falsch (oder bei unless wahr) ist, bricht die 
Schleife sofort ab und macht gar nichts. Manchmal aber möchten Sie einen 
Anweisungsblock zunächst einmal ausführen und erst danach entscheiden, wie es 
weitergeht. Hierfür gibt es do. do-Schleifen haben einen anderen Aufbau als while- 
und until-Schleifen und sehen etwa wie folgt aus (beachten Sie das Semikolon am 
Ende, bei do ist es Pflicht):
do {
   # Schleifenblock
} while (Bedingungsausdruck);
do {
   # Schleifenblock
} until (Bedingungsausdruck);
  Mit diesen beiden Anweisungen werden die Blöcke vor der Auswertung des 
Bedingungsausdrucks ausgeführt. Selbst wenn der Bedingungsausdruck falsch (bei 
while) oder wahr (bei until) ist, wird der Anweisungsblock mindestens einmal 
ausgeführt.

In Wirklichkeit ist
doeine Funktion, die hier nur so tut, als wäre sie eine Schleife (deshalb brauchen Sie auch das Semikolon). Meistens verhältdosich genau wie eine Schleife, nur wenn Sie mit Schleifensteuerbefehlen (wielastodernext) oder mit Labels (Sprungmarken) arbeiten wollen, müssen Sie stattdoeine »echte«while- oderuntil-Schleife verwenden. Schleifensteuerbefehle und Labels besprechen wir noch in dieser Lektion.
In diesem Beispiel spielen wir ein kleines Spiel. Perl bittet Sie um eine Zahl, »zieht« dann eine Zufallszahl zwischen 1 und Ihrer Zahl, und Sie sollen raten, welche es gezogen hat, zum Beispiel:
% zahlraten.pl
Geben Sie die hoechste Zahl ein: 50
Ihr Tipp? (eine Zahl zwischen 1 und 50): 25
Zu hoch!
Ihr Tipp? (eine Zahl zwischen 1 und 50): 10
Zu niedrig!
Ihr Tipp? (eine Zahl zwischen 1 und 50): 17
Zu hoch!
Ihr Tipp? (eine Zahl zwischen 1 und 50): 13
Zu hoch!
Ihr Tipp? (eine Zahl zwischen 1 und 50): 12
Richtig!
Gratuliere! Sie haben mit 5 Versuchen die richtige Zahl erraten.
%
  Das Skript dazu arbeitet mit zwei endlosen while-Schleifen, einer Menge if-
Bedingungen und der rand-Funktion zur Ermittlung einer Zufallszahl. Listing 6.1 zeigt 
den Code.
Listing 6.1: Das Skript zahlraten.pl
1: #!/usr/bin/perl -w
2:
3: $top = 0; # hoechste Zahl
4: $num = 0; # Zufallszahl
5: $count = 0; # zaehlt Versuche
6: $guess = ""; # aktueller Tipp
7:
8: while () {
9: print 'Geben Sie die hoechste Zahl ein: ';
10: chomp($top = <STDIN>);
11: if ($top == 0 || $top eq '0') {
12: print "Das ist keine gute Zahl.\n";
13: }
14: else { last; }
15: }
16:
17: srand;
18: $num = int(rand $top) + 1;
19:
20: while () {
21: print " Ihr Tipp? (eine Zahl zwischen 1 und $top): ";
22: chomp($guess = <STDIN>);
23: if ($guess == 0 || $guess eq '0') {
24: print "Das ist keine gute Zahl.\n";
25: } elsif ($guess < $num) {
26: print "Zu niedrig!\n";
27: $count++;
28: } elsif ($guess > $num) {
29: print "Zu hoch!\n";
30: $count++;
31: } else {
32: print "\a\aRichtig! \n";
33: $count++;
34: last;
35: }
36: }
37: print "Gratuliere! Sie haben mit $count Versuchen";
38: print " die richtige Zahl erraten.\n";
Dieses Skript hat vier Teile: Initialisierung, Eingabe der höchsten Zahl, Auswahl der zu ratenden Zahl und dann das Raten selbst. Den Initialisierungsteil überspringe ich diesmal ganz; Sie werden mittlerweile wissen, wie man Skalarvariablen zuweist.
  In Zeile 8 bis 15 erfragen wir, wie hoch die Zufallszahl höchstens sein darf. Diese 
while-Schleife ist endlos, doch die Bedingung in Zeile 11 soll sicherstellen, dass Sie 
nicht 0 eingeben. Tun Sie es doch, wird eben nicht das last im else-Block, sondern 
die Eingabeschleife von vorn ausgeführt. Denken Sie daran, dass Perl bei der 
Umwandlung von Strings in Zahlen einen String in 0 konvertiert, wenn es keine 
numerischen Daten in ihm findet. Deswegen fängt diese Bedingung sowohl eine 0 als 
auch alle anderen nichtnumerischen Eingaben ab. Perl-Warnungen würden sich bei 
der Eingabe eines Strings trotzdem über »not a number« (»keine Zahl«) beschweren. 
Wenn wir uns in ein paar Tagen mit Mustervergleichen (Pattern Matching) befassen, 
werden Sie einen besseren Weg kennenlernen, diese Warnungen zu umgehen.
  Jedenfalls generieren wir, sobald wir eine brauchbare Zahl haben, in Zeile 17 und 18 
die geheime Zahl, und zwar mit den eingebauten Funktionen srand und rand. Ohne 
Argumente setzt die srand-Funktion den Zufallsgenerator auf die aktuelle Uhrzeit, 
damit wir jedesmal andere Zahlen bekommen (ansonsten wäre es in der Tat ein sehr 
langweiliges Spiel). Die Funktion rand generiert dann eine Zufallszahl zwischen 0 und 
einem Argument, hier unserem $top (einschließlich 0 ohne $top). Wir schneiden diese 
Zahl auf einen Integer zu, addieren 1, damit wir keine Nullen, aber gelegentlich auch 
die eingegebene Höchstzahl erhalten, und speichern sie in der Variablen $num.
  In den Zeilen 20 bis 34 wird geraten. Hier überprüfen wir mit if...elsif-
Anweisungen drei Dinge:
  Wenn der Vorschlag weder zu niedrig noch zu hoch, aber eine gültige Zahl ist, dann 
muss es die richtige Zahl sein - also piepen wir zweimal (okay, Sie vielleicht nicht, 
aber die Escape-Sequenz \a gibt einen Piepton aus), Perl schreibt einen Glückwünsch 
auf den Bildschirm und hört auf.
  Während der Benutzer Zahlen rät, merken wir uns die Anzahl der Versuche in einer 
$count-Variablen. Wir wollen aber nur gültige Versuche zählen,  also inkrementieren 
wir $count nur in den drei Fällen gültiger Zahlen (zu niedrig, zu hoch, richtig). $count 
wird dann mit der Glückwunschmeldung ausgegeben.
  Geht es um die Wiederholung eines Anweisungsblocks, bietet while als »Mutter aller 
Schleifen« immer einen Weg - sie führt einen Block immer wieder aus, und zwar so 
lange (bzw. bis) die Schleifenbedingung erfüllt ist. Die zweite Art von Schleife, die for-
Schleife, löst das gleiche Problem auf etwas andere Art und Weise. Bei for-Schleifen 
wird der Anweisungsblock n-mal hintereinander ausgeführt, dann wird die Schleife 
beendet.
  Sie könnten jede while-Schleife auch als for-Schleife formulieren und umgekehrt. 
Aber für manche Aufgaben bietet sich die eine Form eher an als die andere.
  Perl kennt zwei for-Schleifen: eine allgemeine C-ähnliche for-Schleife und eine dem 
Shell-Skripting entliehene foreach-Schleife, die einen Block »für jedes« (for each) 
Element einer Liste wiederholt.
  Die for-Schleife ist in Perl dieselbe wie in C. Sie setzen eine Lauf- oder Zählervariable 
(zum Beispiel $i) auf einen beliebigen Startwert, überprüfen eine Bedingung, führen 
den Schleifenblock aus, wenn diese erfüllt ist, ändern dann den Wert der 
Laufvariablen, überprüfen wieder die Bedingung, durchlaufen die Schleife 
gegebenenfalls von neuem, ändern wieder die Laufvariable - und so weiter:
for ( Startwert; Bedingungsausdruck; Aenderung ) {
   # Anweisungen
}
  In diesem Beispiel ist Startwert der Ausdruck zum Initialisieren der Laufvariablen, der 
Bedingungsausdruck entscheidet, ob die Iteration weitergeht, und Aenderung 
bestimmt, wie der Wert der Laufvariablen nach jedem Schleifendurchlauf geändert 
wird. Beim ersten Durchlauf wird der Zähler initialisiert, die Bedingung ausgewertet 
und, wenn sie wahr liefert, der Anweisungsblock ausgeführt. Beim zweiten Durchlauf 
wird die Änderungsanweisung ausgeführt, die Bedingung wieder überprüft und wenn 
sie immer noch wahr ist, der Block wieder ausgeführt. So geht es immer weiter, bis 
der Bedingungsausdruck ein falsch zurückgibt.
  Für fünf Schleifendurchläufe könnten Sie zum Beispiel eine for-Schleife wie diese 
verwenden:
for ( $i = 1; $i <= 5; $i++) {
   print "Durchlauf $i\n";
}
Dieser Code-Schnipsel produziert folgende Ausgabe:
Durchlauf 1
Durchlauf 2
Durchlauf 3
Durchlauf 4
Durchlauf 5
  Sie könnten diese Schleife selbstverständlich auch als while-Schleife schreiben:
$i = 1;
while ($i <= 5) {
print "Durchlauf $i\n";
$i++;
}
  Beide Schleifen würden fünfmal durchlaufen, doch die for-Schleife ist kompakter und 
übersichtlicher. Sie listet sozusagen fein säuberlich auf, wo sie anfängt, wo sie aufhört 
und welche Schritte sie dazwischen unternimmt. Für manche Aufgaben eignet sie sich 
besser als eine while-Schleife - beispielsweise, wenn Sie einen begrenzten Satz von 
Werten durchgehen, etwa zum Bearbeiten aller Elemente in einem Array.
  Sie können die Initialisierung, den Bedingungsausdruck oder die Änderungsanweisung 
oder alle drei im oberen Teil der for-Schleife weglassen, nicht jedoch die Semikola. 
Eine endlose for-Schleife könnte zum Beispiel folgendermaßen aussehen:
for ($i = 0; ; $i++) {
   # Anweisungen
}
for (;;) {
   # Anweisungen
}
  Die erste Schleife initialisiert den Schleifenzähler $i und erhöht ihn nach jedem 
Durchlauf um 1. Die zweite Schleife hat nicht einmal eine Zählervariable, sie wird 
einfach nur durchlaufen. Um aus diesen Schleifen herauszukommen, müssen Sie die 
Abbruchbedingung innerhalb der Blöcke festlegen.
Sie wollen die Schleife über mehrere Zähler laufen lassen? Setzen Sie einfach Kommas zwischen Ihre Zählerausdrücke:
for ($i=0, $j=1; $i < 10, j$ < $total; $i++, $j++ ) {
   # Anweisungen
}
In diesem Fall wird die Schleife abgebrochen, wenn einer der beiden Bedingungsausdrücke wahr zurückgibt.
  Die for-Schleife bietet sich an, wenn Sie auf einen konkreten Endpunkt überprüfen 
können - zum Beispiel den höchsten Index in einem Array oder eine bestimmte Zahl. 
foreach ist eine Kurzversion von for ohne expliziten Zähler. foreach durchläuft eine 
Liste und führt den Anweisungsblock so viele Male aus, wie diese Liste Elemente hat.
  Sie kennen foreach bereits - gestern haben wir uns damit durch Listen von Hash-
Schlüsseln gearbeitet. Hier nun die ausführliche »Gebrauchsanweisung« für foreach: 
Sie übergeben der foreach-Schleife eine Liste - zum Beispiel eine Liste aller Schlüssel 
in einem Hash oder einen Bereich. foreach durchläuft die Liste, setzt dabei eine 
temporäre Variable nacheinander auf den Wert jedes Elements und führt für jedes 
Element in der Liste den Anweisungsblock aus.
  Hier ein simples Äquivalent zur for-Schleife von vorhin, die den Zähler fünfmal 
ausgegeben hat:
foreach $zahl (1 .. 5) {
   print "Durchlauf $zahl\n";
}
  Hier erstellt der Bereichsoperator .. eine Liste der Zahlen 1 bis 5, und die foreach-
Schleife arbeitet sich durch diese Liste, wobei sie die Zahlen nacheinander der 
Variablen $zahl zuweist.
  Foreach-Schleifen eignen sich außerordentlich gut zum Durchlaufen von Listen, zum 
Beispiel um die Schlüssel und Werte eines Hash auszugeben, wie Sie gestern gelernt 
haben:
foreach $key (sort keys %hashname) {
   print "Schlüssel: $key Wert: $hashname{$key}\n";
}
  Wie Sie sehen, habe ich die $key-Variablen hier nicht initialisiert (auch die $zahl-
Variable im vorangehenden Beispiel wurde nicht initialisiert). Das ist nicht nötig, weil 
die Variable zwischen foreach und der Liste eine lokale Variable innerhalb der 
Schleife ist - das heißt, vor und nach der Schleife existiert sie gar nicht. Falls sie doch 
schon existiert, Sie also vor der Schleife eine gleichnamige Variable verwenden, 
benutzt foreach sie nur vorübergehend und stellt ihren ursprünglichen Wert wieder 
her, sobald die Schleife verlassen wird. Sie können sich die foreach-Variable als eine 
Art »Kritzel«-Variable vorstellen, die einzig und allein dem kurzen Speichern von 
Elementen dient und beim Schleifenende weggeworfen wird.
Wenn Sie die Werte der Listenelemente gar nicht brauchen, sondern lediglich die Liste durchgehen möchten, können Sie diese Variable auch einfach weglassen.
  In while- und for-Schleifen stehen die Bedingungen, unter denen die Schleife 
durchlaufen bzw. abgebrochen werden soll, ganz am Anfang. In vielen Fällen ist das 
auch genau das Richtige. Wenn Sie aber mit komplexeren Schleifen arbeiten oder mit 
Endlosschleifen spielen, wie ich es in einigen der bisherigen Beispiele getan habe, 
möchten Sie vielleicht auch mitten in der Schleife entscheiden können, wie es von 
diesem Punkt aus weitergehen soll. Und natürlich hat Perl da etwas für Sie: 
Schleifensteuerbefehle.

Wie ich schon erwähnt habe, können Sie in
do-Schleifen keine Schleifensteuerbefehle oder Labels (Sprungmarken) einsetzen. Dafür müßten Sie diedo-Schleife zu einerwhile- ,until- ,for- oderforeach-Schleife umschreiben.
  Mit Schleifensteuerbefehlen steuern Sie den Ablauf einer Schleife. Zwei von ihnen 
haben Sie bereits gesehen: next und last, um die Schleife neu zu starten oder sie 
komplett abzubrechen. Außerdem gibt es in Perl redo und Labels, mit denen Sie Ihren 
Schleifen einen Namen geben können.
  Die Grundbausteine der Schleifensteuerung sind die Schlüsselwörter last, next und 
redo. Sobald eins von ihnen in einer while- oder for-Schleife auftritt, unterbricht Perl 
die normale Schleifenausführung.
Sie können jeden dieser drei Befehle mit einem Label oder für sich allein verwenden. Mit einem Label beziehen sie sich auf die mit diesem Label versehene Schleife ohne Label auf die innerste Schleife (mehr über Labels später). Im einzelnen bewirken sie folgendes:
last wird die Schleife sofort abgebrochen und verlassen (wie bei break in C). 
Der nächste Teil des Skripts wird ausgeführt.
   
 next wird der aktuelle Durchlauf abgebrochen, es wird zurück zum 
Schleifenanfang gesprungen, und der nächste Durchlauf wird mit der 
Überprüfung der Bedingung gestartet. Die Anweisung entspricht dem continue-
Befehl in C. Das Schlüsselwort next ist ein bequemer Weg, unter bestimmten 
Bedingungen den Code im Rest des Anweisungsblocks zu überspringen.
   
 redo wird der aktuelle Schleifendurchlauf abgebrochen und wieder an den 
Anfang gegangen. Der Unterschied zwischen redo und next ist, dass next den 
Bedingungsausdruck am Schleifenanfang noch einmal auswertet (und bei for-
Schleifen die Änderungsanweisung ausführt). Redo hingegen startet erst am 
Anfang des Blocks neu, ohne den Bedingungsausdruck am Schleifenanfang noch 
einmal auszuwerten. Sie können sich den Unterschied so vorstellen, dass redo 
denselben Durchlauf noch einmal wiederholt, während next zum nächsten springt 
(und das ist tatsächlich exakt das, was passiert).
   
  Schauen wir uns noch einmal das Zahlenratespiel an. Wir könnten die zweite while-
Schleife auch so schreiben:
while () {
    print "Ihr Tipp? (eine Zahl zwischen 1 und $top): ";
    chomp($guess = <STDIN>);
    if ($guess == 0 || $guess eq '0') { # wenn Eingabe 0 oder String
        print "Das ist keine gute Zahl.\n";
        next;
    }
    if ($guess < $num)  { # wenn Eingabe zu niedrig
        print "Zu niedrig!\n";
        $count++;
        next;
    }
    if ($guess > $num) { # wenn Eingabe zu hoch
        print "Zu hoch!\n";
        $count++;
        next;
    }
    $count++;
    last;
}
  Weil diese while-Schleife endlos ist, müssen wir mit Schleifensteuerbefehlen innerhalb 
des Schleifenkörpers festlegen, wann sie abgebrochen werden soll - in unserem Fall, 
wenn die richtige Zahl eingegeben wurde. In dem Schleifenblock wird die Eingabe auf 
drei verschiedene Dinge überprüft: ob sie gleich 0 ist, ob sie kleiner als die geheime 
Zahl ist oder ob sie größer als die geheime Zahl ist. In jeder dieser if-Anweisungen 
überspringen wir, wenn eins dieser Kriterien zutrifft, mit next sofort die restlichen 
Anweisungen im Block und gehen zurück zum Schleifenanfang (stünde dort ein 
Bedingungsausdruck, würden wir ihn jetzt aufs neue auswerten). Wenn die 
eingegebene Zahl allen drei Überprüfungen standhält, dann ist es die richtige, und wir 
können die Schleife mit last abbrechen.
Im allgemeinen sind Schleifensteuerbefehle nur notwendig, wenn Sie innerhalb der Schleife auf bestimmte Bedingungen überprüfen, die den normalen Ablauf der Schleife unterbrechen sollen, oder um aus einer Endlosschleife herauszukommen.
  Schleifensteuerbefehle ohne Labels beziehen sich auf die innerste Schleife, das heißt, 
sie unterbrechen die sie unmittelbar umschließende Schleife. Manchmal haben Sie 
aber mehrere ineinandergeschachtelte Schleifen und möchten unter einer bestimmten 
Bedingung aus mehreren Schleifen aussteigen. Aus diesem Grund können Sie 
Schleifen mit Labels kennzeichnen und dann mit last, next und redo zu diesen 
Schleifen springen.
Labels stehen am Anfang der Schleife und werden vereinbarungsgemäß großgeschrieben, damit man sie nicht mit Perl-Schlüsselwörtern durcheinanderbringt. Verwenden Sie einen Doppelpunkt, um das Label von der Schleife zu trennen:
LABEL: while (Bedingungsausdruck) {
   #...
}
  Innerhalb der Schleife verwenden Sie dann last, next oder redo mit dem Label:
LABEL: while (Bedingung_1) {
   #...
   while (Bedingung_2) {
      # ...
      if (noch_eine_Bedingung) {
         last LABEL;
      }
   }
}
  Ihre Labels können Sie nennen, wie Sie wollen, mit zwei Ausnahmen: BEGIN und END 
sind für die Paketkonstruktion und -dekonstruktion reserviert. Mit Paketen (englisch 
Packages) werden wir uns in diesem Buch nicht befassen; lediglich am Tag 13 werde 
ich Ihnen erklären, was ein Paket überhaupt ist. Wenn Sie bereit sind, in 
fortgeschrittene Perl-Konzepte einzusteigen, schauen Sie in der perlmod-Manpage 
nach weitergehenden Informationen über Pakete und Module.
  Hier ein einfaches Beispiel ohne Labels. Die äußere while-Schleife überprüft, ob die 
Variable $exit ungleich dem String 'n' ist. Die innere while-Schleife ist eine 
Endlosschleife.
while ($exit ne 'n') {
   while () {
        print 'Geben Sie eine Zahl ein: ';
        chomp($zahl = <STDIN>);
        unless ($zahl eq '0' ) { # die Zahl 0 ist erlaubt
           if ($zahl == 0 ) {    # wenn Eingabe ein String
              print "Keine Strings.  Zahlen von 0 bis 9, bitte.\n";
              next;
           }
        }
        # andere Anweisungen
        last;
    }
    print 'Eine weitere Zahl ausprobieren (j/n)?: ';
    chomp ($exit = <STDIN>);
}
  In diesem Beispiel verlassen next und last die sie unmittelbar einschließende Schleife 
- also die innere, endlose Schleife, in der Sie die Zahl eingeben. Die äußere Schleife 
wird nur in einem einzigen Fall verlassen: wenn Sie $exit am Ende der äußeren 
Schleife auf 'n' setzen.
  Sagen wir, Sie wollten diesem Skript noch die Möglichkeit hinzufügen, dass man mit 
der Eingabe von exit alle Schleifen und das Skript beenden kann. Dazu würden Sie 
vor die äußere Schleife ein Label setzen:
AUSSEN: while ($exit ne 'n') {
   # etc.
}
  In der inneren Schleife würden Sie dann last mit dem Label verwenden:
AUSSEN: while ($exit ne 'n') {
   while () {
        print 'Geben Sie eine Zahl ein (Beenden mit exit): ';
        chomp($zahl = <STDIN>);
        if ($zahl eq "exit" ) { # schluss, aus, vorbei!
           last AUSSEN;
        }
        # etc.
    }
 #  mehr...
}
  Wenn der Benutzer hier am 'Geben Sie eine Zahl ein'- Prompt »exit« eintippt, 
bezieht sich der last-Befehl auf die Schleife mit dem Label AUSSEN - beendet also in 
diesem Fall die äußere Schleife.
  Beachten Sie, dass Schleifensteuerbefehle sich auf Schleifen beziehen und nicht auf 
eine bestimmte Position im Skript (wie etwa goto, falls Ihnen das etwas sagt). Am 
besten stellt man sich die Labels weniger als Sprungmarken, als vielmehr als 
Bezeichner für Schleifen, die man anspringen kann, vor. Wenn Sie mit einem 
Schleifensteuerbefehl aus einer Schleife herausspringen, springen Sie in Wirklichkeit 
nicht zu dem Label, sondern zur Anweisung direkt hinter der Schleife mit dem Label.
  Glückwunsch! Sie wissen jetzt so gut wie alles, was Sie über Schleifen in Perl wissen 
müssen (das übrige erfahren Sie im Abschnitt »Vertiefung«). Weil wir in dieser Lektion 
noch etwas Platz haben, beende ich sie heute mit zwei allgemeinen Themen: der 
speziellen Variablen $_ und einer einfachen Methode, Dateien zu lesen. Beides 
werden wir in den weiteren Kapiteln dieses Buches häufig gebrauchen.
  Fangen wir mit der $_-Variablen an. Diese spezielle Variable können Sie sich als einen 
Standardplatzhalter für skalare Werte vorstellen. Viele Perl-Konstrukte verwenden $_, 
wenn Sie keine eigene Skalarvariable angeben. Sie können das ausnutzen und Ihre 
Skripts kürzer und effizienter machen - manchmal allerdings auf Kosten der 
Lesbarkeit.
  Betrachten wir ein Beispiel: foreach. Sie erinnern sich, dass die foreach-Schleife mit 
einer temporären Variablen arbeitet, in der die Listenelemente nacheinander 
zwischengespeichert werden. Wenn Sie keine temporäre Variable angeben, speichert 
Perl die Werte in $_ . Innerhalb der Schleife können Sie sich dann auf $_ beziehen, 
um an diesen Wert heranzukommen. Statt
foreach $key (sort keys %hash) {
   print "Schlüssel: $key Wert: $hash{$key}\n";
}
können Sie genausogut schreiben:
foreach (sort keys %hash) {
   print "Schlüssel: $_ Wert: $hash{$_}\n";
}
  Auch viele Funktionen arbeiten mit dem Wert von $_ , wenn Sie ihnen keine 
Argumente übergeben - print und chomp zum Beispiel. Wundern Sie sich also nicht 
über Anweisungen wie:
print;
  Fügen Sie einfach in Gedanken das $_ hinzu:
print $_;
  Wir werden uns die $_-Variable noch genauer ansehen - im nächsten Abschnitt und 
am Tag 9.
  In den Beispielen der letzten Tage haben wir Eingabedaten mit <STDIN> von der 
Tastatur gelesen. Wir haben den Datei-Handle für die Standardeingabe sowohl in 
skalarem als auch in Listenkontext verwendet, und der Unterschied zwischen <STDIN> 
in skalarem Kontext (Zeile für Zeile) und Listenkontext (bis zum Dateiendezeichen) 
sollte Ihnen halbwegs klar sein.
Bestehen Ihre Eingabedaten allerdings aus mehr als nur ein paar Zeilen, ist es äußerst mühsam, sie alle über die Tastatur einzutippen. Das Statistikskript von gestern ist ein gutes Beispiel dafür - es dauert eine ganze Weile, alle Zahlen einzugeben, und wollten wir auch nur einen einzigen Wert hinzufügen, müßten wir komplett von vorne anfangen.
  Viel praktischer wäre es, die Daten in eine eigene Datei zu speichern und von dort zu 
lesen, wenn das Skript ausgeführt wird. Dafür gibt es in Perl zwei Möglichkeiten: Zum 
einen können Sie eine bestimmte Datei innerhalb Ihres Skripts öffnen und lesen. 
Diesem Thema habe ich eine ganze Lektion gewidmet, nämlich Tag 15. Es gibt aber 
noch einen schnelleren Weg, Daten aus beliebigen Daten in ein Perl-Skript 
einzulesen. Diese Technik, die auf dem Perl-Befehl line beruht, bringe ich Ihnen 
heute bei.
  Wir haben den Zeileneingabeoperator <> bis jetzt immer in Zusammenhang mit dem 
Datei-Handle <STDIN> verwendet. Wenn Sie <> aber ohne ein Datei-Handle einsetzen, 
holt Perl sich den Input aus der Datei, die Sie in der Kommandozeile angeben. Ein <> 
ohne Datei-Handle bedeutet im Grunde nichts anderes als: »Nimm alle in der 
Kommandozeile genannten Dateien, öffne sie, verkette sie miteinander und lies sie, 
als wären sie eine einzige Datei.«

Genaugenommen entnimmt Perl die Namen der zu öffnenden und zu lesenden Dateien von einer speziellen Variablen namens
@ARGV, einem Array mit Dateinamen oder anderen in der Kommandozeile angegebenen Werten, und Sie könnten@ARGVim Skript noch verändern. Aber fürs erste nehmen wir einfach an, dass@ARGVdie in der Kommandozeile angegebenen Dateinamen enthält und<>mit diesen arbeitet. Mehr über@ARGVerfahren Sie an Tag 15.
Hier ein Beispiel, das die in der Kommandozeile angegebenen Dateien zeilenweise einliest und jede Zeile nacheinander ausgibt:
while (defined($input = <>)) {
   print "$input";
}

Wenn Sie mit MacPerl arbeiten, haben Sie vielleicht gar keine Kommandozeile und wissen nicht recht, was Sie jetzt machen sollen. Aber keine Angst, es geht auch in MacPerl: Speichern Sie Ihr Skript als Droplet (diese Option finden Sie im Save-Dialog, Menü Type). Ist Ihr Skript als Droplet gespeichert, können Sie die zu lesenden Dateien per Drag & Drop auf das Skript-Icon ziehen - MacPerl wird starten und diese Dateien in das Skript lesen.
  Sagen wir, Sie hätten dieses Beispiel als echodatei.pl gespeichert und möchten die 
Datei eine_Datei.txt ausgeben. Von der Kommandozeile rufen Sie das Skript 
folgendermaßen auf:
% echodatei.pl eine_Datei.txt
Wenn Sie mehrere Dateien ausgeben wollen, hängen Sie einfach alle anderen Dateinamen hinten an die Kommandozeile an:
% echodatei.pl eine_Datei.txt noch_eine_Datei.txt Datei_3.txt
Perl wird all diese Dateien öffnen und eine nach der anderen ausgeben.
  Gehen wir diese while-Schleifenbedingung noch einmal von innen nach außen durch, 
damit Sie verstehen, was hier vor sich geht. Das $input = <> wird Ihnen vertraut 
vorkommen; es ist ähnlich wie beim Lesen einer Zeile mit <STDIN> in skalarem 
Kontext. Vielleicht erinnern Sie sich noch, dass die defined-Funktion wahr oder 
falsch zurückgibt, je nachdem, ob ein Argument definiert ist oder nicht (das heißt, 
nicht den undefinierten Wert enthält). Hier verwenden wir defined, um die Schleife 
beim Dateiende abzubrechen - für jede Zeile der Datei bekommen wir einen gültigen 
Wert, doch am Ende der Datei liefert <> undefiniert zurück - $input wird ebenfalls 
undefiniert, die defined-Funktion liefert falsch, und die while-Schleife wird gestoppt.

Rein technisch gesehen brauchen Sie den
defined-Teil gar nicht. Perl versteht auch so, wo das Dateiende ist, und hört automatisch auf zu lesen. Wenn Sie aber die Warnungen eingeschaltet haben, beschwert Perl sich, dass Sie nicht ausdrücklich auf das Dateiende geprüft haben. Sie können beides umgehen, die Warnung und den Aufruf vondefined, wenn Sie$_als Eingabevariable nehmen (siehe unten).
  Wie bei <STDIN> können die leeren spitzen Klammern sowohl in skalarem als auch im 
Listenkontext verwendet werden. In skalarem Kontext lesen Sie die Eingabedateien 
zeilenweise ein (wobei das Zeilenende ein Zeilenvorschub oder - auf dem Mac - ein 
Carriage Return ist). Im Listenkontext wird jede Zeile der Datei (bzw. der Dateien) als 
ein Element der Liste gespeichert.
  Eine noch kürzere Version des echodatei-Skripts macht von der $_-Variablen 
Gebrauch. Sie können die Variable $input durch $_ ersetzen und auf die temporäre 
Variable und die defined-Funktion komplett verzichten:
while (<>) {
   print;
}
  Wenn die Bedingung einer while-Schleife nichts als einen Zeileneingabeoperator 
enthält, liest diese while-Schleife die Eingabedateien Zeile für Zeile ein, weist jede 
Zeile nacheinander der Variablen $_ zu und bricht ab, wenn <> undefiniert ist, ohne 
dass Sie darauf ausdrücklich überprüfen müßten - Sie erhalten deswegen keine 
Fehlermeldung. Diesen Mechanismus können Sie eigentlich mit jeder Eingabequelle 
verwenden - es funktioniert auch mit <STDIN> oder einem anderen Datei-Handle.
  Beachten Sie allerdings, dass es die while-Schleife ist - nicht der <>-Operator -, die 
die Zeilen nacheinander $_ zuweist und auf das Dateiende überprüft. Sie können zum 
Beispiel nicht do chomp(<>) schreiben; dieser Funktionsaufruf würde die aktuelle Zeile 
nicht in $_ speichern. Dieses besondere Feature haben nur while- und for-Schleifen 
(for-Schleifen werden als »verkleidete« while-Schleifen betrachtet).
Dieser Mechanismus ist ein sehr gebräuchlicher Weg, Daten in ein Perl-Skript einzulesen. In vielen Perl-Skripten werden Ihnen gleich am Skript-Anfang solche Schleifen begegnen, die Daten aus Dateien in ein Array oder einen Hash speichern.
  Betrachten wir ein weiteres Beispiel für den Einsatz von <> und $_ zum Einlesen von 
Daten. Gestern hatten wir ein Skript, das den Benutzer um die Eingabe von ein paar 
Namen bittet und diese dann in ein Array speichert. Die Eingabeschleife dieses Skripts 
sah wie folgt aus:
while () {
     print 'Geben Sie einen Namen ein (Vor- und Nachname): ';
     chomp($in = <STDIN>);
     if ($in ne '') {
         ($fn, $ln) = split(' ', $in);
         $namen{$ln} = $fn;
     }
     else { last; }
}
  Jetzt möchten wir diese Namen aus einer Datei einlesen. Zu diesem Zweck streichen 
wir die Eingabeaufforderung, den Aufruf von <STDIN> und die Überprüfung auf eine 
leere Eingabe:
while (defined($in = <>)) {
    chomp($in);
    ($fn, $ln) = split(" ", $in);
    $namen{$ln} = $fn;
}
  Mit Hilfe der $_-Variablen können wir das Skript noch weiter kürzen:
while (<>) {
    chomp;
    ($fn, $ln) = split(' ');
    $namen{$ln} = $fn;
}
  Obwohl sie kein einziges Mal explizit auftaucht, wird die $_-Variable hier sehr viel 
verwendet: Die while-Schleife weist ihr eine Zeile aus der Input-Datei zu und 
überprüft, ob dieser Wert definiert ist. Dann greift chomp auf diesen Wert zu und 
schneidet den Zeilenvorschub ab. Und split sieht in $_ nach, was es denn splitten 
soll. Derartige Abkürzungen sind in Perl-Skripten sehr häufig.
  Wir könnten sogar die split-Funktion noch weiter abkürzen und das leere Argument 
weglassen. Ohne Argumente trennt split den String in $_ an den Leerstellen:
($fn, $ln) = split;
Wie in den bisherigen Lektionen habe ich Ihnen auch zu Bedingungen und Schleifen noch nicht alles gesagt. Zum Teil möchte ich dies jetzt nachholen und Ihnen einige der bisher ausgelassenen Konzepte vorstellen. Ansonsten steht es Ihnen natürlich frei, auf eigene Faust weiterzuforschen.
  Alle Bedingungen und Schleifen, die Sie heute kennengelernt haben, sind (mit 
Ausnahme von do) komplexe Anweisungen - sie operieren auf Blöcken aus anderen 
Anweisungen und benötigen kein Semikolon am Zeilenende. Daneben besitzt Perl 
auch einen Satz sogenannter Modifikatoren (Modifier) für einfache Anweisungen, mit 
denen Sie bedingungs- und schleifenähnliche Anweisungen erstellen können. 
Manchmal helfen Modifikatoren, einfache Bedingungen und Schleifen noch kürzer 
auszudrücken oder die Logik einer Anweisung besser darzustellen.
  Es gibt vier mögliche Modifikatoren: if, unless, while und until. Jeden dieser 
Modifier können Sie an eine einfache Anweisung anhängen, direkt vor dem 
Semikolon. Hier ein paar Beispiele:
print "$wert" if ($wert < 10);
$z = $x / $y if ($y > 0);
$i++ while ($i < 10);
print $wert until ($wert++ > $maxwert)
  Mit einem Bedingungsmodifikator (if oder unless) wird der vordere Teil der 
Anweisung nur ausgeführt, wenn der Bedingungsausdruck wahr (oder bei unless 
falsch) ist. Mit einem Schleifenmodifikator (while oder until) wird die Anweisung so 
lange ausgeführt, wie der Ausdruck wahr (bzw. bei until falsch) ist.
  Beachten Sie, dass Anweisungen mit while- oder until-Modifikatoren nicht dasselbe 
sind wie normale while- oder until-Schleifen. Sie können sie weder mit 
Schleifensteuerbefehlen wie next oder last kontrollieren noch ihnen Schleifenlabels 
zuweisen.
  Die do-Schleifen, die Sie vorhin in diesem Abschnitt kennengelernt haben, sind genau 
genommen Anweisungen mit Schleifenmodifikatoren. Do ist eine Funktion, die einen 
Anweisungsblock ausführt. Mit den Modifikatoren while und until bestimmen Sie, 
wie oft diese Ausführung wiederholt wird. Deshalb können Sie in do-Schleifen keine 
Schleifensteuerbefehle verwenden.
  Ein continue-Block ist ein optionaler Anweisungsblock nach einer Schleife, der 
ausgeführt wird, wenn der Schleifenblock zu Ende ausgeführt oder die Schleife mit 
next unterbrochen wurde. Der continue-Block wird nicht ausgeführt, wenn Sie die 
Schleife mit last oder redo abbrechen. Nach der Ausführung des continue-Blocks 
macht Perl mit dem nächsten Schleifendurchlauf (also der Auswertung der 
Schleifenbedingung) weiter.
  Sie könnten einen continue-Block zum Beispiel verwenden, um einen Fehler zu 
beheben, der die Schleife unterbrochen hat. Danach läuft die Schleife normal weiter. 
Das ganze sieht folgendermaßen aus (wobei die while-Schleife hier auch eine for- 
oder foreach-Schleife sein könnte):
while ( Bedingung ) {
   # Anweisungen
   if (noch eine Bedingung) {
      # Fehler!
      next;  # (springt zum continue-Block)
   }
   # weitere Anweisungen
} continue {
   # behebe Fehler
   # (danach geht's am Schleifenanfang weiter)
}

Beachten Sie, dass
continuein Perl etwas anderes ist als dascontinuein C - dessen Perl-Pendant istnext.
  Bemerkenswerterweise hat Perl keine explizite switch- (oder, je nach Ihrer 
Lieblingssprache, auch case-) Anweisung. Eine switch-Anweisung (Schalter, Weiche) 
ist eine Fallunterscheidung, mit der Sie einen Wert überprüfen, und viel kompakter, 
übersichtlicher und oft auch effizienter als eine Konstruktion aus zahllosen if und 
elsif, um festzulegen, was bei welchem Ergebnis geschehen soll.
  Ein solches switch-Konstrukt können Sie in Perl jedoch »nachahmen«. Hier erweisen 
sich freistehende Blöcke (bare blocks) als äußerst nützlich. Für freistehende Blöcke 
gelten die gleichen Regeln wie für Schleifenblöcke; deswegen können Sie sie mit 
Labels versehen, mit redo erneut ausführen oder mit last und next verlassen (next 
führt einen eventuell vorhandenen continue-Block aus, last nicht). Das nutzen wir 
aus und schreiben unser »Perl-Switch« zum Beispiel so:
SWITCH: {
   $a eq "eins" && do {
                       $a = 1;
                       last SWITCH;
                     };
   $a eq "zwei" && do {
                       $a = 2;
                       last SWITCH;
                     };
   $a eq "drei" && do {
                       $a = 3;
                       last SWITCH;
                       };
# und so weiter
}
Mit Pattern Matching (Mustervergleichen) geht es noch kürzer. Ich komme darauf zurück, wenn wir uns an Tag 9 mit Pattern Matching und regulären Ausdrücken befassen.
  Ja, Perl unterstützt das verschriene goto (englisch »gehe zu«). Es ist in keinem Fall 
empfehlenswert, doch wenn Sie denn unbedingt wollen, können Sie goto auf drei 
Arten einsetzen:
goto LABEL, wobei das Label irgendwo in Ihrem Skript stehen kann, in diesem 
Fall also wirklich eine Sprungmarke ist.
   
 goto AUSDRUCK, wobei der Ausdruck zu einem Labelnamen ausgewertet werden 
muss.
   
 goto &NAME, was nicht wirklich ein goto ist - es ersetzt eine laufende Unterroutine 
durch die Unterroutine &NAME. Es wird beim automatischen Laden von 
Subroutinen in Pakete genutzt.
   
  Falls Sie sich für weitere goto-Details interessieren, schauen Sie in die perlsyn-
Manpage.
Mit Bedingungen und Schleifen können Sie je nach Situation entscheiden, wie sich Ihr Skript verhalten soll. Diese Kontrollstrukturen sind so wichtig, dass wir schon seit dem zweiten Tag - lange bevor wir zu dieser Lektion gekommen sind - in den Beispielen mit ihnen gearbeitet haben.
  Bedingungsanweisungen zweigen zu unterschiedlichen Anweisungsblöcken ab, 
abhängig davon, ob eine Bedingung erfüllt ist oder nicht. Sie haben die Konstrukte if, 
if...else und if...elsif kennengelernt, den Bedingungsoperator (?...:), der in 
andere Ausdrücke eingebaut werden kann, und Sie haben gesehen, wie Sie logische 
Operatoren (&&, ||, and und or) zur Steuerung des Programmflusses einsetzen 
können.
  Als nächstes haben wir Schleifen behandelt: insbesondere die while-Schleifen, die 
einen Anweisungsblock so lange ausführen, wie die Schleifenbedingung wahr ist. Sie 
haben das Gegenstück, die until-Schleife, kennengelernt, die abbricht, wenn die 
Bedingung wahr ist. In diesem Zusammenhang haben wir auch die do-Schleifen 
(do...while und do...until) und ihre Besonderheiten besprochen - beispielsweise dass 
sie gar keine echten Schleifen sind.
  Die zweite Art von Schleife ist die for-Schleife, die ebenfalls Anweisungsblöcke 
wiederholt, aber geeigneter ist, wenn die Anzahl der Durchläufe von vornherein 
feststeht. Sie haben die for-Schleife mit ihrer C-ähnlichen Zählersyntax und die 
foreach-Schleife zum Durchlaufen aller Elemente in einer Liste kennengelernt.
  Dann habe ich erklärt, wie Sie mit den Schleifensteuerbefehlen next, last und redo 
die Ausführung eines Blocks abbrechen und Teile der Schleife überspringen sowie in 
verschachtelten Schleifen eine bestimmte, mit einem Label versehene Schleife 
ansteuern können.
  Schließlich haben wir die Lektion wie die beiden letzten Lektionen mit weiteren 
Anmerkungen zum Thema Eingabe beendet. Diesmal haben Sie gelernt, wie Sie mit 
der <>-Syntax aus Dateien lesen und mit der Variablen $_ viele Operationen 
abkürzen können.
Mit der heutigen Lektion haben Sie sich die Grundlagen zu Perl vollständig angeeignet. Morgen werden wir die Woche mit einigen längeren Beispielen abschließen. Nächste Woche geht es nicht bloß weiter, nächste Woche legen wir richtig los und widmen uns einigen der mächtigsten und aufregendsten Perl-Features, darunter Pattern Matching (Mustervergleiche) und allerlei Listenakrobatik.
Sie haben heute folgende Perl-Funktionen kennengelernt:
do, eine Funktion, die sich wie eine Schleife mit einem while oder until am 
Ende benimmt
   
 rand, das eine Zufallszahl zwischen 0 und ihrem Argument generiert,
   
 srand, den von rand verwendeten Zufallsgenerator initialisiert. Ohne Argument 
nimmt srand die aktuelle Uhrzeit als Startwert.
   
Mehr Details finden Sie - wie bereits erwähnt - in der perlfunc-Manpage.
Frage:
 Ich habe den Eindruck, dass for-Schleifen auch als while-Schleifen geschrieben 
werden könnten und umgekehrt.
Antwort:
 Ja, das könnten sie mit Sicherheit. Aber es geht darum, was Sie sich 
vorstellen, eine »wiederhole x-mal«- oder eine »wiederhole so lange, bis«-
Schleife. Sie sollen dann nicht noch darüber nachdenken müssen, wie Sie die 
eine in die andere umformulieren. Es ist eine der angenehmsten 
Eigenschaften von Perl, dass es in der Lage ist, sich an Ihre Denkweise 
anzupassen. Übrigens kennen sogar die weit weniger »entgegenkommenden« 
Sprachen C und Java while- und for-Schleifen.
Frage:
 Ich habe versucht, mit continue eine Schleife abzubrechen, und Perl hat mit 
Fehlermeldungen um sich geworfen. Was habe ich falsch gemacht?
Antwort:
 Sie haben vergessen, dass continue in Perl nicht zum Abbrechen von 
Schleifen verwendet wird (oder Sie haben diesen Abschnitt übersprungen). 
Die Entsprechung zum continue von C ist in Perl next. Verwenden Sie 
continue nur als optionalen Anweisungsblock, der am Ende eines Blocks 
ausgeführt werden soll (siehe Vertiefungsabschnitt).
Frage:
 Ich habe mir Ihre beiden Beispiele für das Lesen aus Dateien angesehen. Eines 
der Beispiele verwendet $_, das andere nicht. Das erste ist zwar kürzer, aber wenn 
man nicht weiß, welche Operationen mit $_ arbeiten, ist es kaum zu verstehen. 
Ich finde, dass die Lesbarkeit eines Skripts ein paar mehr Buchstaben wert ist.
Antwort:
 Das ist definitiv ein guter Grundsatz, dem auch viele Perl-Programmierer 
folgen. »Schleichwege« über die $_-Variable machen das Skript zwar kürzer, 
aber bestimmt auch weniger verständlich. In manchen Fällen - wie zum 
Beispiel für Eingaben mit <> - ist der Einsatz von $_ jedoch eine Art 
weitverbreitete »Redensart«, die, sobald Sie sich daran gewöhnt haben, auch 
vernünftig und verständlich scheint. Wenn Sie Skripts von anderen lesen oder 
verändern müssen, werden Sie wahrscheinlich recht bald auf mysteriöses $_-
Verhalten stoßen. Achten Sie also auf $_, setzen Sie es ein, wo es wirklich 
angemessen ist, oder vermeiden Sie es, wenn es Ihrer Meinung nach die 
Lesbarkeit zu sehr einschränkt. Die Entscheidung liegt ganz bei Ihnen.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.
if und unless?
 while-Schleife abgebrochen?
 do-Schleifen anders als while- oder until-Schleifen?
 for-Schleife? Was machen sie?
 next, last und redo.
 $_ verwendet werden kann.
 <> von <STDIN>?
    if ($wert == 4) then { print $wert; }
elseif ($wert > 4) { print "mehr als 4"; }
     for ($i = 0, $i < $max, $i++) {
   $werte[$i] = "";
}
     while ($i < $max) {
   $werte[$i] = 0;
}
 namen.pl so um, dass es die Namen aus einer Datei liest 
(wenn Sie gestern die Übungsaufgabe 3 gelöst haben, also auch mit Zweitnamen 
umgehen können, schreiben Sie diese Version entsprechend neu).
Hier die Antworten auf die Workshop-Fragen aus dem vorigen Abschnitt.
{}) umgebene Gruppe von Perl-
Anweisungen (die andere Blöcke enthalten kann). Blöcke werden meistens im 
Zusammenhang mit Bedingungen und Schleifen gebraucht, können aber auch 
allein, als freistehende Blöcke, verwendet werden (bare blocks).
 if-Anweisung führt ihren Block aus, wenn der Bedingungsausdruck zu wahr 
ausgewertet wird, unless führt ihn aus, wenn die Bedingung falsch ergibt.
 while-Schleife bricht ab, wenn ihr Bedingungsausdruck falsch zurückgibt.
 do-Schleifen unterscheiden sich in zweierlei Hinsicht von while- oder until-
Schleifen. Zum einen werden ihre Blöcke vor der ersten Überprüfung, also 
mindestens einmal, ausgeführt. Zum anderen können Sie keine 
Schleifensteuerbefehle wie last oder next in einer do-Schleife verwenden, weil do 
gar keine echte Schleife, sondern eigentlich eine Funktion mit einem Modifikator 
ist.
 for-Schleife sind:
 $i = 0.
 $i < $max.
 $i++.
 next, last und redo sind Schleifensteuerbefehele. next bricht den aktuellen 
Durchlauf ab und startet am Schleifenanfang den nächsten, inklusive der 
Überprüfung der Bedingung in einer for- oder while-Schleife. Auch redo bricht 
den aktuellen Durchlauf ab, startet aber am Anfang des Blocks, ohne die 
Schleifenbedingung zu überprüfen. last beendet die Schleife ebenso komplett wie 
abrupt - es prüft nichts, startet nichts, es steigt einfach aus.
 $_ verwendet, wenn Sie keine Variable 
angegeben:
 	 while (<>) weist $_ jede Zeile einzeln zu.
 	 chomp entfernt den Zeilenvorschub vom String in $_.
 	 foreach verwendet $_ als temporäre Schleifenvariable.
 <> wird verwendet, um die Inhalte von Dateien einzulesen, die über die 
Kommandozeile angegeben (und in @ARGV gespeichert) werden. Mit <STDIN> 
liest man Daten von der Standardeingabe (normalerweise der Tastatur) ein.
#!/usr/bin/perl -w
$zahl1 = 0;
$zahl2 = 0;
while () {
print 'Geben Sie die erste Zahl ein: ';
chomp($zahl1 = <STDIN>);
print 'Geben Sie die zweite Zahl ein: ';
chomp($zahl2 = <STDIN>);
if ($zahl1 < 0 || $zahl2 < 0) {
print "Keine negativen Zahlen!\n";
next;
} elsif ( $zahl2 == 0) {
print "Die zweite Zahl darf nicht 0 sein!\n";
next;
} else { last; }
}
print "$zahl1 geteilt durch $zahl2 ist ";
printf("%.2f\n", $zahl1 / $zahl2 );
elseif ist kein gültiges Perl-Schlüsselwort, nehmen Sie statt 
dessen elsif. then ist ebenfalls kein gültiges Perl-Schlüsselwort.
 for-Bedingungsausdrucks müssen mit Semikola, 
nicht mit Kommata getrennt werden.
 $i wird innerhalb 
der Schleife nicht inkrementiert.
 #!/usr/bin/perl -w
%names = (); # Hash: Namen
@raw = (); # temp: rohe Woerter
$fn = ''; # Vorname
while (<>) {
chomp;
@raw = split(" ", $_);
if ($#raw == 1) { # Normalfall: zwei Woerter
$names{$raw[1]} = $raw[0];
} else { # den Vornamen zusammensetzen
$fn = '';
for ($i = 0; $i < $#raw; $i++) {
$fn .= $raw[$i] . " ";
}
$names{$raw[$#raw]} = $fn;
}
}
foreach $lastname (sort keys %names) {
print "$lastname, $names{$lastname}\n";
}




