|
Um Maßnahmen abhängig von bestimmten Kriterien durchführen zu können, müssen Kontrollstrukturen eingesetzt werden, welche in der Lage sind festgelegte Zustände zu erfassen, zu vergleichen, sie auszuwerten und abschließend die vom Programmierer vorgesehenen Aktionen durchzuführen.
Hier kommen die bedingten Anweisungen zum Einsatz. Oft auch einfach nur Bedingungen genannt. Die Shell bietet dem Programmierer dazu im Wesentlichen zwei Bedingungskonstrukte an, mit denen sich wohl alle erdenklichen Bedingungen realisieren lassen:
Die if-Abfrage eignet sich immer dann, wenn man komplexe Bedingungen prüfen möchte, da in ihrem Konstrukt der test-Befehl, bzw. dessen alternative Schreibweise zur Formulierung der Bedingung eingesetzt wird. In der einfachsten Form ist die if-Abfrage mit folgendem Konstrukt zu realisieren:

if [ Formulierung ] then Kommando fi
Anmerkung: Die Einrückung des Kommandos hat keinen funktionalen Charakter. Dies dient lediglich der besseren Lesbarkeit.
In der erweiterten Form lässt sich das Konstrukt noch durch elif und else erweitern, so dass beliebig viele Bedingungen geprüft werden können und abschließend auch darauf reagiert werden kann, wenn keine der zuvor geprüften Bedingung erfüllt worden sind:

if [ Formulierung_1 ] # Wenn Formulierung_1 wahr liefert, then Kommando # dann führe Kommando aus und verlasse das if-Konstrukt elif [ Formulierung_2 ] # Wenn Formulierung_2 wahr liefert, then Kommando # dann führe Kommando aus und verlasse das if-Konstrukt elif [ Formulierung_3 ] #Wenn Formulierung_3 wahr liefert, then Kommando # dann führe Kommando aus und verlasse das if-Konstrukt else #Wenn keine Formulierung wahr liefert, Kommando # dann führe Kommando aus und verlasse das if-Konstrukt fi
Dieses Konstrukt hat vier Bedingungen, denn auch das letzte Kommando setzt eine Bedingung voraus. Nämlich dass keine Formulierung zuvor zutraf (wahr war). Zudem hat das if-Konstrukt die Eigenschaft alle weiteren Prüfungen zu übergehen, sobald eine Bedingung erfüllt worden ist. Dann wird nur noch das entsprechende Kommando ausgeführt und das if-Konstrukt wird verlassen
Das obige Konstrukt soll nun in einem einfachen Script umgesetzt werden, um die Funktionsweise zu belegen:

#!/bin/bash
if [ -f /boot ] then echo 'Die Formulierung -f /boot lieferte wahr zurück!' elif [ 9 -lt 8 ] then echo 'Die Formulierung 9 -lt 8 lieferte wahr zurück!' elif [ 'Hallo Welt!' = 'Hallo Welt!' ] then echo 'Die Formulierung Hallo Welt! = Hallo Welt! lieferte wahr zurück!' else echo 'Keine Formulierung lieferte wahr zurück!' fi

Die Formulierung 'Hallo Welt!' = 'Hallo Welt!' lieferte wahr zurück!
Dieses Script führt, wie zu erwarten, lediglich den echo-Befehl der dritten Bedingung aus. Die erste Formulierung liefert unwahr zurück (Rückgabewert 1), denn /boot ist ein Verzeichnis und keine Datei. Also wird die nächste Formulierung geprüft. Diese liefert ebenfalls unwahr zurück, denn 9 ist nicht kleiner als 8. Die dritte Formulierung schließlich liefert wahr zurück (Rückgabewert 0), da beide Strings identisch sind. Respektive wird das if-Konstrukt nun verlassen, weshalb auch die else-Bedingung nicht mehr zum Tragen kommt.
Eine weiters Abfragekonstrukt für Bedingungen ist die case-Abfrage. Aufgrund der Arbeitsweise eignet es sich hervorragend, um Muster zu vergleichen. Im case-Konstrukt wird dazu ein Wert oder eine Variable angegeben, die darauf folgend auf Muster-Übereinstimmung geprüft wird. Der Wert oder die Variable wird auch Selector oder Expression (Ausdruck) genannt. Dabei ist beim Vergleich zwischen Selector und Muster nicht nur die Groß- und Kleinschreibung von Bedeutung, was unter Linux ja ohnehin immer der Fall ist. Das Muster muss zudem genau auf den kompletten Selector passen.
Wie auch die if-Abfrage unterstützt die case-Abfrage beliebig viele Formulierungen, die hier Muster genannt werden. Des Weiteren bietet sie ebenfalls die Möglichkeit auf den Fall zu reagieren, wenn kein Muster mit dem Selector übereinstimmt.
Im Folgenden das case-Konstrukt mit drei Mustern und dem Fall, dass kein Muster zutrifft ( *) ):

case Selector in Muster_1) Kommando ;; # Muster_1 trifft auf Selector zu -> Kommando -> verlassen Muster_2) Kommando ;; # Muster_2 trifft auf Selector zu -> Kommando -> verlassen Muster_3) Kommando ;; # Muster_3 trifft auf Selector zu -> Kommando -> verlassen *) Kommando # Kein Muster trifft auf Selector zu -> Kommando -> verlassen esac
Auch hier wird das case-Konstrukt sofort verlassen, sobald ein Muster auf den Selector zutrifft und das entsprechende Kommando ausgeführt wurde. Der Fall, dass kein Muster zutrifft tritt auch ein, wenn der selector Null ist oder einen Leerstring enthällt.
Da der Selector ein String ist (auch Zahlen werden als String behandelt), sind bei den Mustern auch Wildcards möglich. Ebenso lassen sich mehrere Muster in einem logischen Oder verknüpfen.
Dazu folgt nun ein Script, welches die Arbeitsweise verständlicher darstellen soll. Wie fast immer wird für das Kommando der echo-Befehl gewählt, da er das Resultat für den Benutzer sofort sichtbar macht:

#!/bin/bash
read myVar # Einlesen der Benutzereingabe in die Variable myVar
case $myVar in a) echo 'Sie haben a eingegeben!' ;; b) echo 'Sie haben b eingegeben!' ;; c) echo 'Sie haben c eingegeben!' ;; d|e|f) echo "Sie haben $myVar eingegeben!" ;; *z*) echo "Das Wort $myVar enthält ein z!" ;; *) echo 'Sie haben weder a, b, c noch d oder e oder f eingegeben! Des Weiteren auch keine Zeichenfolge, welche den Buchstaben z enthält!' esac
Nach dem Start des Scripts erwartet es eine Benutzereingabe. Ist diese durchgeführt, wird das case-Konstrukt abgearbeitet und die vorgegebenen Muster auf Übereinstimmung mit der Benutzereingabe geprüft. Zu welcher Ausgabe es kommt, hängt nun von dem Ergebnis der Prüfung ab.
Gibt man ein a ein, dann trifft direkt das erste Muster zu, es kommt zur entsprechenden Ausgabe und das Konstrukt wird verlassen und da sonst kein weiterer Code folgt, endet auch das Script. Gibt man e ein, dann trifft dass vierte Muster zu, denn die Bedingung ist d oder e oder f. Wird das Wort ritz eingegeben, dann entspricht dies der Bedingung des fünften Musters, denn es enthält den Buchstaben z. Und trifft keine Bedinung zu, erfolgt die Ausgabe hinter *).
Was aber würde passieren, wenn man das Wort amazonas eingeben würde? Dieses Wort beginnt mit einem a, enthält aber zusätzlich den Buchstaben z. Besser noch, man gibt das Wort mit Leerstellen ein, also a m a z o n a s. Hier könnte doch eventuell der IFS (hier Leerzeichen) zum tragen kommen.
Trotzdem, in beiden Fällen trifft nur das fünfte Muster zu. Denn wie zu Beginn erwähnt, muss das Muster auf den kompletten Selector passen. Und eben aus diesem Grund eignet sich die case-Abfrage so gut für den Mustervergleich.
Abschließend sei noch angemerkt, dass jedes if-Konstrukt durch ein case-Konstrukt (und umgekehrt) ersetzt werden kann. Je nach Ziel kommen dabei aber teilweise unnötig kompizierte Konstrukte heraus. Letztendlich sollte man deshalb immer den einfacheren Weg wählen, weshalb beide bedingte Anweisungen ihre Berechtigung haben. |