Start Shellprogrammierung Bedingte Anweisungen
Bedingte Anweisungen E-Mail
Geschrieben von: tpm   

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:

  • if-Abfrage
  • case-Abfrage

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:

 

example

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:

 

example

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:

 

script

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

 

output

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 ( *) ):

 

example

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:

 

script

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

Zuletzt aktualisiert am Samstag, den 15. Januar 2011 um 14:03 Uhr