4.8 Die Anweisung case
Die Anweisung case wird oft als Alternative zu mehreren if–elif-Verzweigungen verwendet. Allerdings überprüft case im Gegensatz zu if oder elif nicht den Rückgabewert eines Kommandos. case vergleicht einen bestimmten Wert mit einer Liste von anderen Werten. Findet hierbei eine Übereinstimmung statt, können einzelne oder mehrere Kommandos ausgeführt werden. Außerdem bietet eine case-Abfrage im Gegensatz zu einer if–elif-Abfrage erheblich mehr Übersicht (siehe Abbildung 4.10). Hier die Syntax, wie Sie eine Fallunterscheidung mit case formulieren:
case "$var" in
muster1) kommando
...
kommando ;;
muster2) kommando
...
kommando ;;
mustern) kommando
...
kommando ;;
esac
Die Zeichenkette »var« nach dem Schlüsselwort case wird nun von oben nach unten mit den verschiedensten Mustern verglichen, bis ein Muster gefunden wurde, das auf »var« passt oder eben nicht. In der Syntaxbeschreibung wird bspw. zuerst »muster1« mit »var« verglichen. Stimmt »muster1« mit »var« überein, werden entsprechende Kommandos ausgeführt, die sich hinter dem betroffenen Muster befinden. Stimmt »var« nicht mit »muster1« überein, wird das nächste Muster »muster2« mit »var« verglichen. Dies geht so lange weiter, bis eine entsprechende Übereinstimmung gefunden wird. Wird keine Übereinstimmung gefunden, werden alle Befehle der case-Anweisung ignoriert und die Ausführung hinter esac fortgeführt.
Eine sehr wichtige Rolle spielen auch die doppelten Semikolons (;;). Denn stimmt ein Muster mit »var« überein, werden die entsprechenden Befehle dahinter bis zu diesen doppelten Semikolons ausgeführt. Wenn die Shell auf diese Semikolons stößt, wird aus der case-Verzweigung herausgesprungen (oder der Muster-Befehlsblock beendet) und hinter esac mit der Scriptausführung fortgefahren. Würden hier keine doppelten Semikolons stehen, so würde die Shell weiter fortfahren (von oben nach unten), Muster zu testen. Ebenfalls von Bedeutung: Jedes Muster wird mit einer runden Klammer abgeschlossen, um es von den folgenden Kommandos abzugrenzen. Es darf aber auch das Muster zwischen zwei Klammern ( muster ) gesetzt werden. Dies verhindert, dass bei Verwendung von case in einer Kommando-Substitution ein Syntaxfehler auftritt. Abgeschlossen wird die ganze case-Anweisung mit esac (case rückwärts geschrieben).
Das Muster selbst kann ein String sein oder eines der bereits bekannten Metazeichen *, ? oder [ ]. Ebenso können Sie eine Muster-Alternative wie *(...|...|...); @(...|...|...) usw. der Bash und der Korn-Shell aus Abschnitt 1.10.8 einsetzen. Sollten Sie diese Sonderzeichen in Ihren Mustern setzen, so dürfen die Muster nicht zwischen Anführungszeichen stehen.
Der Wert von »var« muss nicht zwangsläufig eine Zeichenkette, sondern kann auch ein Ausdruck sein, der eine Zeichenkette zurückliefert. Es empfiehlt sich allerdings immer, »var« zwischen Double Quotes einzuschließen, um eventuell einen Syntaxfehler bei leeren oder nicht gesetzten Variablen zu vermeiden.
Ein simples Beispiel:
# Demonstriert die case-Anweisung
# acase1
tag=`date +%a`
case "$tag" in
Mo) echo "Mo : Backup Datenbank machen" ;;
Di) echo "Di : Backup Rechner Saurus" ;;
Mi) echo "Mi : Backup Rechner Home" ;;
Do) echo "Do : Backup Datenbank machen" ;;
Fr) echo "Fr : Backup Rechner Saurus" ;;
Sa) echo "Sa : Backup Rechner Home" ;;
So) echo "So : Sämtliche Backups auf CD-R sichern" ;;
esac
Im Beispiel wurde mit einer Kommando-Substitution der aktuelle Tag an die Variable tag übergeben. Anschließend wird in der case-Anweisung entsprechender Tag ausgewertet und ausgegeben. Hängen Sie jetzt hierbei statt einer simplen Ausgabe einige sinnvolle Befehle an und lassen jeden Tag den cron-Daemon darüber laufen, haben Sie ein echtes Backup-Script, das Ihnen Woche für Woche die ganze Arbeit abnimmt. Natürlich muss dies nicht unbedingt ein Backup-Script sein, es können auch bestimmte Log-Dateien ausgewertet werden.
4.8.1 Alternative Vergleichsmuster
Um gleich wieder auf das Script »acase1« zurückzukommen: Ein Problem, das hierbei auftreten kann, ist, dass die deutsche Schreibweise für den Wochentag verwendet wurde. Was aber, wenn die Umgebung in einer englischsprachigen Welt liegt, in der eben die Wochentage »Mon«, »Tue«, »Wed«, »Thu«, »Fri«, »Sat« und »Sun« heißen? Hierzu bietet Ihnen case in der Auswahlliste alternative Vergleichsmuster an. Sie können mehrere Muster zur Auswahl stellen. Die Muster werden mit dem bitweisen ODER-( | )-Operator getrennt.
case "$var" in
muster1a|muster1b|muster1c) kommando
...
kommando ;;
muster2a|muster2b|muster2c) kommando
...
kommando ;;
muster3a|muster3b|muster3c) kommando
...
kommando ;;
esac
Wenden Sie dies nun auf das Script »acase1« an, so haben Sie ein Script erstellt, das sowohl die Ausgabe des deutschen als auch des englischsprachigen Wochentags akzeptiert.
# Demonstriert die case-Anweisung und die
# alternativen Vergleichsmuster
# acase2
tag=`date +%a`
case "$tag" in
Mo|Mon) echo "Mo : Backup Datenbank machen" ;;
Di|Tue) echo "Di : Backup Rechner Saurus" ;;
Mi|Wed) echo "Mi : Backup Rechner Home" ;;
Do|Thu) echo "Do : Backup Datenbank machen" ;;
Fr|Fri) echo "Fr : Backup Rechner Saurus" ;;
Sa|Sat) echo "Sa : Backup Rechner Home" ;;
So|Sun) echo "So : Sämtliche Backups auf CD-R sichern" ;;
esac
Das Beispiel kann man nochmals verkürzen, da ja am Montag und Donnerstag, Dienstag und Freitag sowie Mittwoch und Samstag dieselbe Arbeit gemacht wird.
# Demonstriert die case-Anweisung und die alternativen Vergleichsmuster
# acase3
tag=`date +%a`
case "$tag" in
Mo|Mon|Do|Thu) echo "$tag : Backup Datenbank machen" ;;
Di|Tue|Fr|Fri) echo "$tag : Backup Rechner Saurus" ;;
Mi|Wed|Sa|Sat) echo "$tag : Backup Rechner Home" ;;
So|Sun) echo "So : Sämtliche Backups auf CD-R sichern" ;;
esac
4.8.2 case und Wildcards
Bei den Mustern der case-Anweisung sind auch alle Wildcard-Zeichen erlaubt, die Sie von der Dateinamen-Substitution her kennen. Die Muster-Alternativen wie bspw. *(...|...|...); @(...|...|...) bleiben weiterhin nur der Bash und der Korn-Shell vorbehalten. Auch hier kann wieder z. B. das Script »acase3« einspringen. Wenn alle Tage überprüft wurden, ist es eigentlich nicht mehr erforderlich, den Sonntag zu überprüfen. Hierfür könnte man jetzt theoretisch auch das Wildcard-Zeichen * verwenden.
# Demonstriert die case-Anweisung und die
# alternativen Vergleichsmuster mit Wildcards
# acase4
tag=`date +%a`
case "$tag" in
Mo|Mon|Do|Thu) echo "$tag : Backup Datenbank machen" ;;
Di|Tue|Fr|Fri) echo "$tag : Backup Rechner Saurus" ;;
Mi|Wed|Sa|Sat) echo "$tag : Backup Rechner Home" ;;
*) echo "So : Sämtliche Backups auf CD-R sichern" ;;
esac
Das Wildcard-Zeichen wird in einer case-Anweisung immer als letztes Alternativ-Muster eingesetzt, wenn bei den Mustervergleichen zuvor keine Übereinstimmung gefunden wurde. Somit führt der Vergleich mit * immer zum Erfolg und wird folglich auch immer ausgeführt, wenn keines der Mustervergleiche zuvor gepasst hat. Das * steht im Vergleich zur if-elif-Verzweigung für die else-Alternative.
Die Wildcards [] lassen sich bspw. hervorragend einsetzen, wenn Sie nicht sicher sein können, ob der Anwender Groß- und/oder Kleinbuchstaben bei der Eingabe verwendet. Wollen Sie bspw. überprüfen, ob der Benutzer für eine Ja-Antwort, »j«, »J« oder »ja« bzw. »Ja« oder »JA« verwendet hat, können Sie dies folgendermaßen mit den Wildcards [] vornehmen.
# Demonstriert die case-Anweisung mit Wildcards
# acase5
# Als erstes Argument angeben
case "$1" in
[jJ] ) echo "Ja!" ;;
[jJ][aA]) echo "Ja!" ;;
[nN]) echo "Nein!" ;;
[nN][eE][iI][nN]) echo "Nein!" ;;
*) echo "Usage $0 [ja] [nein]" ;;
esac
Das Script bei der Ausführung:
you@host > ./acase1
Usage ./acase1 [ja] [nein]
you@host > ./acase1 j
Ja!
you@host > ./acase1 jA
Ja!
you@host > ./acase1 nEIn
Nein!
you@host > ./acase1 N
Nein!
you@host > ./acase1 n
Nein!
you@host > ./acase1 Ja
Ja!
Das Ganze lässt sich natürlich mit Vergleichsmustern wiederum erheblich verkürzen:
# Demonstriert die case-Anweisung mit Wildcards und
# alternativen Mustervergleichen
# acase6
# Als erstes Argument angeben
case "$1" in
[jJ]|[jJ][aA]) echo "Ja!" ;;
[nN]|[nN][eE][iI][nN]) echo "Nein!" ;;
*) echo "Usage $0 [ja] [nein]" ;;
esac
4.8.3 case und Optionen
Zu guter Letzt eignet sich case hervorragend zum Auswerten von Optionen in der Kommandozeile. Ein einfaches Beispiel:
# Demonstriert die case-Anweisung zum Auswerten von Optionen
# acase7
# Als erstes Argument angeben
case "$1" in
-[tT]|-test) echo "Option \"test\" aufgerufen" ;;
-[hH]|-help|-hilfe) echo "Option \"hilfe\" aufgerufen" ;;
*) echo "($1) Unbekannte Option aufgerufen!"
esac
Das Script bei der Ausführung:
you@host > ./acase1 -t
Option "test" aufgerufen
you@host > ./acase1 -test
Option "test" aufgerufen
you@host > ./acase1 -h
Option "hilfe" aufgerufen
you@host > ./acase1 -hilfe
Option "hilfe" aufgerufen
you@host > ./acase1 -H
Option "hilfe" aufgerufen
you@host > ./acase1 -zzz
(-zzz) Unbekannte Option aufgerufen!
Sie können hierfür wie gewohnt die Optionen der Kommandozeile mit dem Kommando getopts (siehe Abschnitt 3.8) auswerten, zum Beispiel:
# Demonstriert die case-Anweisung zum Auswerten von
# Optionen mit getopts
# acase8
while getopts tThH opt 2>/dev/null
do
case $opt in
t|T) echo "Option test";;
h|H) echo "Option hilfe";;
?) echo "($0): Ein Fehler bei der Optionsangabe"
esac
done
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.
|