7.5 Bedingte Anweisungen
Auch in der Shell können bedingte Anweisungen verwendet werden. Wir werden uns im Folgenden die bereits aus awk in ähnlicher Form bekannte if-Anweisung und später die case-Anweisung ansehen, die jeweils eine Möglichkeit zur Implementierung bedingter Anweisungen in Shellskripts darstellen.
7.5.1 if
Die bedingte Anweisung, die man am häufigsten verwendet, ist die if-Anweisung. Sie hat einen einfachen Aufbau, wobei man stets darauf achten sollte, die nötigen Leerzeichen um die eckigen Klammern zu setzen. Hinter dem if-Befehl selbst folgt die in der Regel in eckigen Klammern eingeschlossene Bedingung. Darauf folgt das Schlüsselwort then, das die Anweisungen einleitet, die abgearbeitet werden sollen, sofern diese Bedingung erfüllt ist.
elif
Ist die erste Bedingung nicht erfüllt, wird – sofern vorhanden – die nächste Bedingung über elif geprüft. Ist auch diese Bedingung nicht erfüllt, werden die restlichen elif-Bedingungen so lange überprüft, bis entweder eine Bedingung erfüllt oder keine weitere elif-Bedingung mehr vorhanden ist.
else
Sind alle Bedingungen nicht erfüllt, werden – sofern vorhanden – die Anweisungen hinter dem else-Schlüsselwort ausgeführt.
fi
Die if-Anweisung wird durch das Schlüsselwort fi beendet.
if [ Bedingung ] then Anweisung1 Anweisung2 ... elif [ Bedingung2 ] then Anweisung1 Anweisung2 ... elif [ BedingungN ] then Anweisung1 Anweisung2 ... else Anweisung1 Anweisung2 ... fi
Listing 7.19 if
Eine if-Anweisung muss weder eine elif- noch eine else-Anweisung beinhalten.
Es ist auch möglich, den Skriptcode für eine if-Anweisung in einer zeilensparenden und gleichzeitig übersichtlicheren Form zu schreiben, sofern man die Separierung durch Kommata verwendet. <Man kann auch die komplette if-Anweisung inklusive sämtlicher Sub-Bedingungen und Anweisungen in eine einzelne Zeile, separiert durch Kommata, schreiben. Dies ist allerdings sehr unübersichtlich und soll nur der Vollständigkeit halber erwähnt werden.> Diese Methode werden wir in den restlichen Beispielen dieses Kapitels anwenden.
if [ Bedingung ]; then Anweisung1 Anweisung2 ... elif [ Bedingung2 ]; then Anweisung1 Anweisung2 ... elif [ BedingungN ]; then Anweisung1 Anweisung2 ... else Anweisung1 Anweisung2 ... fi
Listing 7.20 if kürzer fassen
Die Klammern
Wirft man einen Blick in das Dateisystem, wird man beispielsweise unter OpenBSD im Verzeichnis /bin den Dateinamen »[« vorfinden.
Dabei handelt es sich um ein ausführbares Programm namens test. Tatsächlich ist die Syntax der if-Anweisung in der Form
if Testbefehl; then Anweisungen fi
Listing 7.21 if-Anweisung: richtige Syntax
aufgebaut. Das Programm test erlaubt uns nun, eine Bedingung zu erstellen. Ist diese Bedingung erfüllt, gibt test »wahr« bzw. im anderen Fall »falsch« an if zurück. Sie können jedoch auch jedes andere Programm in eine if-Anweisung einbauen:
$ if test 1; then echo "Test"; fi Test $ if /bin/ls >/dev/null; then echo "Test"; fi Test $ if /bin/gibtsnicht; then echo "blah"; else echo "Fehler"; fi bash: /bin/gibtsnicht: No such file or directory Fehler
Listing 7.22 test
Zahlen-Vergleiche
Doch nun zurück zu den eigentlichen Bedingungen, die uns das Programm test bietet. Zunächst werden wir uns ansehen, wie Vergleiche zwischen Zahlenwerten programmiert werden. Dabei gibt es verschiedene Möglichkeiten, dies zu tun. Wir werden uns mit der einfachsten und unserer Meinung nach besten Möglichkeit beschäftigen. Dazu verwendet man vier runde an Stelle zweier eckiger Klammern und die bereits aus awk bekannten Vergleichsoperatoren wie ==, != oder =>:
if (( 17 < 20 )); then echo "17 ist kleiner als 20" else echo "hier stimmt irgendetwas nicht..." fi
Listing 7.23 Zahlen-Vergleich
String-Vergleiche
Möchte man hingegen Strings vergleichen, sei zunächst angemerkt, dass man bei diesen auch reguläre Ausdrücke einbauen kann. Ein String wird dabei in Anführungszeichen gestellt, was auch für Variablen gilt.
# direkter Stringvergleich: if [ "abc" = "abc" ]; then echo "Bedingung ist wahr." fi # Variablen mit Strings A="abc" if [ "$A" = "abc" ]; then echo "Bedingung ist wahr." fi # reguläre Ausdrücke (Achtung: Doppelklammer!) if [[ "$A" == a?? ]]; then echo "Bedingung ist wahr." fi
Listing 7.24 Stings vergleichen
7.5.2 case
Die Shell stellt mit case jedoch noch eine Option zur Verfügung, mit der eine bedingte Anweisung in Skripts eingebaut werden kann.
Bei case werden die möglichen »Fälle«, die eintreten können, explizit angegeben, was in folgender Form geschieht, wobei Testwert in der Regel eine Variable ist:
case Testwert in Fall1) Anweisung1; Anweisung2; ;; Fall2) Anweisung1; Anweisung2; ;; esac
Listing 7.25 case
else für case
Das von der if-Anweisung bekannte else-Schlüsselwort finden wir in ähnlicher Form (nämlich durch den Fall »*«) auch für die case-Anweisung vor. Der Fall *) enthält dabei die Anweisungen, die ausgeführt werden sollen, wenn keiner der zuvor aufgeführten Fälle eintritt.
Ein Anweisungsblock für einen Fall ist durch zwei Semikolons abzuschließen.
Im folgenden Beispiel soll gezeigt werden, wie der *)-Fall und die Abschlusssequenz angewandt werden.
ZAHL=5 case $ZAHL in 3) echo "Die Zahl ist 3!" ;; 4) echo "Die Zahl ist 4!" ;; *) echo "Zahl ist nicht 3 oder 4!" ;; esac
Listing 7.26 case-Beispiel
Etwas kompakter
Möchte man nun nicht für jeden Fall, für den ein ähnlicher oder gar gleicher Skriptcode ausgeführt werden soll, den Anweisungsblock neu schreiben, kann man sich Arbeit ersparen und sogar einen an Übersichtlichkeit gewinnenen Code erstellen, wenn man Bedingungen zusammenfasst. Dazu verwendet man die Oder-Bedingung. Ein Fall ist dabei erfüllt, wenn zumindest eine einzige der angegebenen Möglichkeiten zutrifft.
ZAHL=3 case $ZAHL in 3|4) echo "Die Zahl ist 3 oder 4!" ;; *) echo "Zahl ist nicht 3 oder 4!" ;; esac
Listing 7.27 Die kompakte Version