8.7    Bedingte Anweisungen

Bedingte Anweisungen sind ein elementarer Grundstein der Programmierung. Mit diesen Bedingungen können Werte abgefragt werden, und es kann entsprechend darauf reagiert werden.

Ein einfaches Beispiel dafür ist folgendes: Die Benutzerinnen und Benutzer sollen in einem Programm angeben, ob sie einen Ausdruck ihres Dokuments haben möchten. Das Programm muss nun die Benutzereingaben prüfen und sie zum Beispiel in einer Variablen speichern. Enthält die Variable den Wert »Ja«, erfolgt der Ausdruck, andernfalls wird ganz einfach davon abgesehen.

Zur Formulierung von bedingten Anweisungen verwendet man in der Regel die if-Anweisung (es gibt weitere Möglichkeiten, die wir weiter unten behandeln möchten). Sie hat folgende Syntax:

if [ BedingungA ] && [ BedingungB ]
then
       Anweisungen
elif [ BedingungA ]
then
       Anweisungen
else
       Anweisungen
fi                     # nicht mit 'if' verwechseln!

Listing 8.33     Die if-Anweisung

Die if-Anweisung in Zeile 1 legt die Grundbedingung fest. Ist diese erfüllt, werden die Anweisungen ausgeführt, die hinter dem then-Schlüsselwort stehen. Ist die Bedingung jedoch nicht erfüllt, wird geprüft, ob die elif-Bedingung – sofern vorhanden – erfüllt ist, und deren Anweisungen werden ausgeführt. Ist auch diese nicht erfüllt, wird zur nächsten elif-Anweisung gesprungen, bis es keine weitere mehr gibt. Existiert zudem eine else-Anweisung, wird sie nur ausgeführt, falls alle anderen Bedingungen nicht zutrafen.

Bedingungen können auch verknüpft werden: Ein && beispielsweise bedeutet, dass sowohl Bedingung 1 als auch Bedingung 2 erfüllt sein müssen, damit die Anweisungen ausgeführt werden. Des Weiteren gibt es die Negierung (!) – die Bedingung ist also erfüllt, wenn ihr Inhalt nicht erfüllt wurde. Außerdem können Sie das »ODER« (||) verwenden, bei dem nur eine der verknüpften Bedingungen erfüllt sein muss.

Es gibt eine ganze Menge Möglichkeiten, Bedingungen zu formulieren, die um einiges über String-Vergleiche hinausgehen. So können Sie prüfen, ob eine Datei existiert oder eine bestimmte Datei ein Verzeichnis ist. Da dieser Abschnitt lediglich zur Einführung in die Shellskript-Programmierung dient, werden wir Sie nicht auch noch damit quälen.

Das folgende Skript prüft, ob ein Wert als erster Parameter übergeben wurde und, wenn ja, welcher Wert, und führt eine bedingte Anweisung aus. Der Parameter -z in einer Bedingung prüft, ob das angegebene Element leer ist. Beachten Sie bitte, dass Variablen, deren Inhalt in Form eines Strings verglichen werden soll, in Anführungszeichen geschrieben werden müssen.

#!/bin/sh

if [ -z $1 ]
then
      echo "Erforderlicher Parameter fehlt!"
elif [ "$1" = "backup" ]
then
      echo "Erstelle Backup."
      …
elif [ "$1" = "restore" ]
then
      echo "Spiele Sicherungsdaten wieder ein."
      …
else
      echo "Unbekannter Parameter."
fi

Listing 8.34     Bedingte Anweisungen

8.7.1    Vergleichen von Zahlen

Oftmals hat man es mit Zahlen zu tun. Diese werden allerdings auf spezielle Arten verglichen. Tabelle 8.1 listet die Vergleichsmöglichkeiten auf.

Vergleich

Beschreibung

$a -eq $b

Die verglichenen Werte sind gleich (equal).

$a -ne $b

Die Werte sind ungleich (not equal).

$a -lt $b

$a ist kleiner als $b.

$a -le $b

$a ist kleiner als/gleich $b.

$a -gt $b

$a ist größer als $b.

$a -ge $b

$a ist größer als/gleich $b.

Tabelle 8.1     Bedingungen für Zahlen

Würden wir das obige Beispiel anhand von Zahlenvergleichen realisieren, wäre zum Beispiel folgende Bedingung denkbar:

elif [ $1 -eq 1 ]
then
      echo "Erstelle Backup."
fi

Listing 8.35     Ein typischer Zahlenvergleich

8.7.2    Returncodes für Bedingungen nutzen

Mithilfe von Returncodes ist es möglich, den Erfolg eines ausgeführten Programms zu überprüfen. Führt ein Shellskript beispielsweise ein Backup vom Verzeichnis /export/home/nobody durch und existiert das Verzeichnis nicht, sollte das Programm einen entsprechenden Fehlercode zurückgeben. In der Regel steht eine 0 für eine erfolgreiche Programmausführung, eine 1 für eine fehlerhafte.

Fehlercodes werden immer in der Shellvariablen $? hinterlegt.

user$ ls Datei
Datei
user$ echo $?
0
user$ ls DateiABCD
ls: DateiABCD: No such file or directory
user$ echo $?
1
user$ ls /root 2>/dev/null 1>output
user$ if [ $? -eq 1 ]; then
then> echo "Programmausführung fehlerhaft, breche Skript ab."
then> fi
Programmausführung fehlerhaft, breche Skript ab.

Listing 8.36     Prüfen des Rückgabewertes

8.7.3    Case-Bedingungen

Beschäftigen wir uns noch mit einer weiteren Möglichkeit, bedingte Anweisungen zu programmieren, nämlich mit der case-Anweisung. Der Nachteil dieser Anweisung ist, dass sie nur einen Wert verarbeitet. Das ist aber auch gleichzeitig ihr Vorteil gegenüber der Anweisung if. Möchten Sie nämlich dort eine Variable auf mehrere Werte überprüfen, so müssen Sie jeweils elsif-Bedingungen formulieren. case bietet dafür eine kürzere und bessere Schreibweise.

Die Syntax von case ist folgendermaßen aufgebaut:

case "$VARIABLE" in
  WertA)
      Anweisungen für A
      ;;
  WertB)
      Anweisungen für B
      ;;
  WertC|WertD|WertE)
      Gemeinsame Anweisungen für die Werte C, D und E
      ;;
  *)
      Anweisungen
      ;;
esac

Listing 8.37     case-Syntax

Die Werte WertA und WertB werden für die Variable $VARIABLE überprüft. enthält die $VARIABLE einen dieser Werte, werden die entsprechenden Anweisungen ausgeführt. Die beiden Semikola beenden den Anweisungsbereich. Der letzte Werte-Test (*) ist das else der if-Anweisung, das immer dann greift, wenn obige Werte nicht mit dem Variablenwert übereinstimmten.

Die case-Anweisung wird in der Regel für die Erstellung von Runlevel-Skripten (besonders unter Solaris) verwendet. Man übergibt dem Skript dabei ein Argument $1, das Werte wie start oder stop enthält, um einen Dienst automatisch beim Wechseln in ein bestimmtes Target (oder durch manuellen Start des Skripts) zu starten bzw. zu beenden. Skripte, die Kommandos im Hintergrund ausführen, können Sie auf diese Art und Weise wundervoll stoppen und starten. Das folgende Skript wendet dieses Verfahren an, um den syslog-Daemon zu starten bzw. anzuhalten.

#!/bin/bash

case "$1" in
   start)
        echo "starte syslogd"
        /usr/sbin/syslogd
        ;;
   hup|restart)
        echo "rekonfiguriere syslogd"
        pkill -HUP syslogd
        ;;
   stop)
        echo "stoppe syslogd"
        pkill syslogd
        ;;
   *)
        # Fehler abfangen
        echo "Kommando unbekannt!"
        ;;
esac

Listing 8.38     Start/Stopp-Skript