8.8 Schleifen
Sie verfügen nun über das notwendige Grundwissen, um Schleifen zu verstehen. Einer Schleife wird eine Bedingung übergeben. Ist diese erfüllt, werden ihre Anweisungen so lange ausgeführt, bis diese Bedingung nicht mehr erfüllt ist.
Eine Bedingung ist sowohl in einer Schleife als auch in einer case-Verzweigung oder if-Anweisung immer wahr, wenn sie den Wert 1 ergibt. Probieren Sie einmal folgende Anweisung aus:
user$ if [ 1 ] then echo wahr fi wahr // diese Zeile ist bereits die Ausgabe der if-Anweisung user$
Listing 8.39 Eine immer wahre if-Anweisung
Bei einer Schleife würde der Befehl echo wahr so lange ausgeführt, bis die Bedingung der Schleife nicht mehr erfüllt wäre.
8.8.1 Die while-Schleife
Die Syntax der while-Schleife ist im folgenden Listing abgebildet. Die Anweisungen werden mit dem do-Schlüsselwort eingeleitet und mit done beendet.
while [ Bedingung ] do Anweisung A Anweisung B … done
Listing 8.40 Syntax der while-Schleife
Doch in der Praxis lernt man bekanntlich am besten. Im Folgenden wird eine Endlosschleife erstellt, die alle 30 Minuten die verfügbare Kapazität der Datenträger überprüft. Sinkt die verbliebene freie Kapazität auf unter 5 % (der df-Befehl gibt in diesem Fall einen Wert von über 95 % für die genutzte Kapazität an), wird eine Meldung ausgegeben. Das Prozentzeichen wird mit dem sed-Programm herausgefiltert. awk und sed haben wir in Kapitel 6 besprochen.
#!/bin/bash while [ 1 ] do df -h | grep -v '[Uu]se' | sed s/\%// | \ awk '{ if($5>95) print $1 " is almost full. ("$5"%)" }' sleep 1800 done
Listing 8.41 Endlosschleife
8.8.2 Die for-Schleife
Die for-Schleife bietet gegenüber der while-Schleife einen Vorteil: Sie kann eine Liste von Werten durcharbeiten. Das heißt, die Schleife wird für jeden angegebenen Wert einmal durchlaufen. Dabei wird einer Variablen für jeden Schleifendurchlauf ein weiterer zuvor angegebener Wert zugewiesen, mit dem Sie innerhalb des Anweisungsblocks arbeiten können. Dies ist beispielsweise sehr nützlich, wenn eine Liste von Dateien verarbeitet werden soll.
for VAR in Werte do AnweisungA AnweisungB … done
Listing 8.42 Syntax der for-Schleife
Stellen Sie sich einmal vor, dass alle Benutzerverzeichnisse archiviert werden sollen. Die Benutzerverzeichnisse der Benutzer, die mit dem Buchstaben »A« beginnen, sind im Verzeichnis /home/a abgelegt, die derjenigen, die mit »B« beginnen, sind in /home/b/ untergebracht usw. Als Archivmedien stehen der Veranschaulichung halber – Achtung, eher praxisfern – USB-Sticks mit einer Kapazität von 2 GByte zur Verfügung und die Benutzer-Quotas beschränken sich pro Buchstabenverzeichnis auf genau diese Kapazität.
Mit der for-Schleife können wir nun ein simples Skript entwickeln, das jeweils ein Verzeichnis auf einem Stick sichert und Sie danach auffordert, den nächsten Stick einzustecken.
#!/bin/bash USBSTICK=/dev/sde1 TARGET=/mnt/stick for DIR in /home/*; do # Ist es ein Verzeichnis? if [ -d $DIR ]; then mount -t vfat $USBSTICK $TARGET if [ $? -eq 0 ] then cp -r $DIR $TARGET umount $TARGET echo "Bitte nächstes Medium einlegen." else echo "Mountvorgang schlug fehl!" exit fi fi done
Listing 8.43 Ein einfaches Backup
Im Optimalfall sollte noch die verfügbare Kapazität auf dem Medium überprüft und mit dem tar-Kommando eine Komprimierung erzielt werden. Doch hätten wir dies gezeigt, wäre wohl das eigentliche Ziel, nämlich die Demonstration der for-Schleife, untergegangen.
8.8.3 seq – Schleifen mit Aufzählungen
Manchmal möchte man eine Schleife "uber eine Ziffernfolge durchlaufen oder benötigt aus irgendeinem anderen Grund eine Ziffernfolge. Dafür wurde das Programm seq geschrieben, das hier nur kurz angesprochen werden soll. Eine Parameterliste für seq finden Sie in der Kommandoreferenz.
Soll seq beispielsweise alle Zahlen von 1 bis 10 auflisten, dann ist dies ganz einfach. Übergeben Sie den Start- und Endwert:
$ seq 1 10 1 2 3 4 5 6 7 8 9 10
Listing 8.44 seq in Aktion
Möchten Sie seq in eine Schleife packen, so nutzen Sie am besten die Kommandosubstitution. Wollen Sie etwa einen bestimmten Satz Dateien löschen, dann wäre Folgendes eine Möglichkeit:
$ for i in `seq 1 10`; do rm "file$i" done
Listing 8.45 seq in einer for-Schleife
8.8.4 until
Zu den bereits bekannten Schleifen kommt noch die until-Schleife hinzu. Diese neue Schleife kann als Negation der while-Schleife verstanden werden. Der Anweisungsblock der until-Schleife wird so lange ausgeführt, wie die Bedingung nicht erfüllt ist. Man kann praktisch die until-Schleife mit einer while !-Schleife gleichsetzen:
while [ ! 1 ]; do echo Test; done
until [ 1 ]; do echo Test; done
# oder noch kürzer:
until :; do echo Test; done
Listing 8.46 until und while !
8.8.5 break – Schleifen abbrechen
Um eine Schleife mitten im Durchlauf an einer beliebigen Stelle zu verlassen, setzen Sie dort das break-Schlüsselwort. Dies funktioniert sowohl mit while- als auch mit for- und until-Schleifen.
Da die select-Anweisung wie eine Schleife fungiert, können Sie sie durch (Strg) + (D) abbrechen, oder Sie integrieren eine Abbruchfunktion, in der Sie break verwenden. Letzteres ließe sich folgendermaßen umsetzen:
#!/bin/bash
echo "Was haben Sie für ein Haustier?"
select HAUSTIER in Hund Katze Beenden
do
if [ "$HAUSTIER" = "Beenden" ]; then break; fi
echo "Sie haben also ein/eine(n) $HAUSTIER"
echo "Kann Ihr Haustier auch in Common-Lisp programmieren?"
done
Listing 8.47 select-Beispiel