Eine der grundlegendsten Dinge beim Programmieren ist die Überprüfung von verschiedenen Bedingungen, um damit auf bestimmte Gegebenheiten zu reagieren. Die Überprüfung von Bdingungen hat in der Regel bei Programmiersprachen zwei verschiedene Formen, die if-Anweisung und eine Mehrfachauswahl. Beide werden von der Shell unterstützt.

1. Die if-Anweisung

1.1 Die einfache if-Anweisung

Grundsätzlich hat die if-Anweisung der Bourne-Shell eine sehr einfache Form. Nach dem if steht ein Befehl, der ausgeführt wird. Gibt dieses Kommando eine 0 als Rückgabewert zurück, so gilt die Bedingung als erfüllt und die Aktionen, die zwischen dem folgenden then und fi stehen werden ausgeführt.

if Kommando 
then 
  Aktion 
  Aktion 
  ...
fi

Natürlich sind die Aktionen auch wieder normale Unix-Befehle. Das „fi“, das den Block beendet, der durch „if … then“ begonnen wurde, ist einfach nur das „if“ rückwärts geschrieben.

1.2 Das Programm test

Damit es jetzt sinnvolle Möglichkeiten gibt, Bedingungen zu überprüfen brauchen wir ein Programm, das verschiedene Tests durchführt und jeweils bei gelungenem Test eine 0 als Rückgabewert zurückgibt, bei mislingenem Test eine 1. Dieses Programm heißt test und ermöglicht alle wesentlichen Bedingungsüberprüfungen, die für das Shell-Programmieren notwendig sind.

Damit wir nicht jedesmal schreiben müssen

if test ...

gibt es einen symbolischen Link auf das Programm test, der einfach [ heißt. Allerdings verlangt das Programm test, wenn es merkt, dass es als [ aufgerufen wurde, auch als letzten Parameter eine eckige Klammer zu. Damit ist es also möglich zu schreiben:

if [ ... ]

Wichtig ist hierbei, dass unbedingt ein Leerzeichen zwischen if und der Klammer und zwischen der Klammer und den eigentlichen Tests stehen muß. Es handelt sich bei der Klammer ja tatsächlich um einen Programmaufruf!

1.3 Die verschiedenen Bedingungsüberprüfungen mit test bzw. [

-r Dateiname

Die Datei Dateiname existiert und ist lesbar

-w Dateiname

Die Datei Dateiname existiert und ist beschreibbar

-x Dateiname

Die Datei Dateiname existiert und ist ausführbar

-d Dateiname

Die Datei Dateiname existiert und ist ein Verzeichnis

-s Dateiname

Die Datei Dateiname existiert und ist nicht leer

-b Dateiname

Die Datei Dateiname existiert und ist ein blockorientiertes Gerät

-c Dateiname

Die Datei Dateiname existiert und ist ein zeichenorientiertes Gerät

-g Dateiname

Die Datei Dateiname existiert und das SGID-Bit ist gesetzt

-k Dateiname

Die Datei Dateiname existiert und das Sticky-Bit ist gesetzt

-u Dateiname

Die Datei Dateiname existiert und das SUID-Bit ist gesetzt

-p Dateiname

Die Datei Dateiname existiert und ist ein Named Pipe

-e Dateiname

Die Datei Dateiname existiert

-f Dateiname

Die Datei Dateiname existiert und ist eine reguläre Datei

-L Dateiname

Die Datei Dateiname existiert und ist ein symbolischer Link

-S Dateiname

Die Datei Dateiname existiert und ist ein Socket

-O Dateiname

Die Datei Dateiname existiert und ist Eigentum des Anwenders, unter dessen UID das test-Programm gerade läuft

-G Dateiname

Die Datei Dateiname existiert und gehört zu der Gruppe, zu der der User gehört, unter dessen UID das test-Programm gerade läuft

Datei1 -nt Datei2

Datei1 ist neuer als Datei2 (newer than)

Datei1 -ot Datei2

Datei1 ist älter als Datei2 (older than)

Datei1 -ef Datei2

Datei1 und Datei2 benutzen die gleiche I-Node (equal file)

-z Zeichenkette

Wahr wenn Zeichenkette eine Länge von Null hat.

-n Zeichenkette

Wahr wenn Zeichenkette eine Länge von größer als Null hat.

Zeichenkette1 = Zeichenkette2

Wahr wenn Zeichenkette1 gleich Zeichenkette2

Zeichenkette1 != Zeichenkette2

Wahr wenn Zeichenkette1 ungleich Zeichenkette2

Wert1 -eq Wert2

Wahr, wenn Wert1 gleich Wert2 (equal)

Wert1 -ne Wert2

Wahr, wenn Wert1 ungleich Wert2 (not equal)

Wert1 -gt Wert2

Wahr, wenn Wert1 größer Wert2 (greater than)

Wert1 -ge Wert2

Wahr, wenn Wert1 größer oder gleich Wert2 (greater or equal)

Wert1 -lt Wert2

Wahr, wenn Wert1 kleiner Wert2 (less than)

Wert1 -le Wert2

Wahr, wenn Wert1 kleiner oder gleich Wert2 (less or equal)

!Ausdruck

Logische Verneinung von Ausdruck

Ausdruck -a Ausdruck

Logisches UND. Wahr, wenn beide Ausdrücke wahr sind

Ausdruck -o Ausdruck

Logisches ODER. Wahr wenn mindestens einer der beiden Ausdrücke wahr ist

Mit diesen Tests sind so ziemlich alle denkbaren Bedingungsüberprüfungen möglich, die in einem Shellscript notwendig sind.

1.4 Die erweiterte if-else Anweisung

Natürlich bietet die if-Anweisung auch eine Erweiterung zur normalen Form, die sogenannte if-else Anweisung. Es ist also möglich zu schreiben:

if [ Ausdruck ]
then
  Kommandos
else
  Kommandos
fi

1.5 Die if-elif-else Anweisung

Um noch einen Schritt weiterzugehen bietet die if-Anweisung sogar ein weiteres if im else, das sogenannte elif, das wieder eine Bedingung überprüft:

if [ Ausdruck ]
then
  Kommandos
elif [ Ausdruck ]
then
  Kommandos
else
  Kommandos
fi

2. Mehrfachauswahl mit case

Oft kommt es vor, dass eine Variable ausgewertet werden muß und es dabei viele verschiedenen Möglichkeiten gibt, welche Werte diese Variable annehmen kann. Natürlich wäre es mit einer langen if-elif-elif-elif… Anweisung möglich, so etwas zu realisieren, das wäre aber sowohl umständlich, als auch schwer zu lesen. Damit solche Fälle einfacher realisiert werden können, gibt es die Mehrfachauswahl mit case. Der prinzipielle Aufbau einer case-Entscheidung sieht folgendermaßen aus:

case Variable in
  Muster1) Kommando1 ;;
  Muster2) Kommando2 ;;
  Muster3) Kommando3 ;;
  ...
esac

Zu beachten sind zunächst die Klammern, die das Muster abschließen. Das Kommando, das zum jeweiligen Muster passt muß mit zwei Strichpunkten abgeschlossen werden. Statt einem Kommando können nämlich auch mehrere Kommandos, durch Strichpunkt getrennt stehen. Nur die doppelten Strichpunkte machen der Shell klar, dass das Kommando für den bestimmten Fall jetzt fertig ist.

Der Abschluß mit esac ist wieder einfach das Wort case rückwärts geschrieben.