Listing 12
#!/bin/sh while true; do echo $0 $$ $PPID sleep 30 done
Die Trap-Anweisung zum Abfangen von Signalen hat die Form trap ErsatzkommandoSignal. Geben Sie kein Kommando als Ersatz an, ignoriert das Skript das Signal lediglich. Listing 13 demonstriert das Abfangen eines Signals per trap in der Praxis. Senden Sie das Signal 10 oder SIGUSR1 an das Programm, zeigt es die Belegung der Massenspeicher im Rechner an.
Listing 13
#!/bin/sh # Signale ignorieren trap '' 2 20 # Auf Signal 10 reagieren trap 'df -h' 10 while true; do echo "$$: $a" sleep 3 done
Verzweigungen und Schleifen
Das Skript aus Listing 14 bildet ein Auswahlmenü mitsamt eines Untermenüs ab. Es setzt die folgenden Anforderungen um:
- Komfortable Eingabe über die Tastatur mit je einem Tastendruck.
- Auswerten der Eingabe, sodass fehlerhafte Eingaben nicht auf dem Bildschirm erscheinen.
- Für jede Auswahl gibt es genau eine Eingabemöglichkeit.
Listing 14
#!/bin/bash
while true; do
# Bildschirm löschen
clear
# Hauptmenü
echo "(1) Punkt 1"
echo "(2) zum Untermenü"
echo "(9) Beenden"
# Auswahl einlesen, einstellig
read -n1 -p "Aufgabe: " auf
# Auswertung. Zahlenwerte als String
# verhindern Fehleranzeigen, falls
# Buchstaben gedrückt werden
if [ "$auf" = "1" ]; then
echo "Punkt 1"
sleep 5
elif [ "$auf" = "2" ]; then
# neue Schleife
while true; do
# Bildschirm löschen
clear
# Untermenü
echo "(a) Punkt a "
echo "(b) Punkt b "
echo "(z) zurück"
read -n1 -p "Aufgabe: " umenu
if [ "$umenu" = "a" ]; then
echo "Punkt a"
sleep 5
elif [ "$umenu" = "b" ]; then
echo "Punkt b"
sleep 5
elif [ "$umenu" = "z" ]; then
# Zurück zum Hauptmenü
break
fi
done
elif [ "$auf" = "9" ]; then
# Skriptende
break
fi
done
clear
echo "Skriptende"
Um das Beispiel einfach zu gestalten, besteht jede Funktion nur aus der Zeile echo "Punkt N", deren Ausgabe für jeweils fünf Sekunden auf dem Bildschirm verbleibt. Für das Hauptmenü stehen drei Möglichkeiten bereit, von denen eine das Skript beendet und eine weitere das Untermenü startet. Beim Beenden zeigt das Skript eine abschließende Nachricht an. Das Untermenü enthält wieder drei Punkte, wobei einer zum Rücksprung ins Hauptmenü dient. Zum Löschen des Bildschirms kommt clear zum Einsatz.
Einige der bereits im vorigen Teil des Workshops angesprochenen Techniken finden sich in diesem Programm wieder. Zum Einlesen der Eingabe steht bei read eine Länge der Zeichenkette von 1; der Anwender braucht also nicht mehr [Eingabe] zu drücken.
Um Fehlermeldungen aufgrund nicht numerischer Zeichen bei test zu vermeiden, vergleichen Sie einfach Zeichenketten anstelle numerischer Werte. Drückt der Benutzer eine Taste, die einem Buchstaben zugeordnet ist, erzeugt das keine Fehlermeldung.
Für das Untermenü starten Sie eine zweite While-Schleife, die das Programm ausschließlich über break wieder verlassen kann. Die Nachricht beim Beenden des Skripts schreiben Sie ans Dateiende, wo das Skript bei einem Abbruch der Schleife via break landet. Alternativ wäre es möglich, die Nachricht vor ein exit innerhalb des If-Konstrukts zu setzen.
Ein weiteres Skript (Listing 15) demonstriert, wie Sie einen Wert, der in einer Datei (im Beispiel lang.conf) hinterlegt ist, wieder auslesen und nutzen. Die möglichen Werte lauten de für die deutsche und en für die englische Sprache. Das Skript liest diese Datei beim Programmstart aus, erstellt das Menü mit drei Punkten: je einem zum Einstellen der Sprache und einem zum Beenden. Die Texte für das Menü liegen in deutscher und in englischer Sprache vor, die Auswahl innerhalb der Menüpunkte gelingt mit Klein- wie Großbuchstaben.
Listing 15
#!/bin/bash
# Auslesen Spracheinstellungen
sprache=$(cat lang.conf)
# Menütext anzeigen, Aufgabe abfragen
while true; do
if [ "$sprache" = "de" ]; then
clear
echo -e "(a) Punkt 1\n(b) Punkt 2\n(c) Punkt 3\n(s) Spracheinstellungen\n(e) Ende"
read -n1 -p "Aufgabe: " aufg
elif [ "$sprache" = "en" ]; then
clear
echo -e "(a) first\n(b) second\n(c) third\n(l) Language\n(q) Quit"
read -n1 -p "Task: " aufg
else
echo "Fehler in der Spracheinstellung"
exit
fi
case "$aufg" in
[aA])
echo "1"; sleep 5; ;;
[bB])
echo "2"; sleep 5; ;;
[cC])
echo "3"; sleep 5; ;;
[sS]|[lL])
while true; do
clear
echo "(1) Deutsch"
echo "(2) English"
read -n1 -p "Sprache/Language: " ehcarps
if [ "$ehcarps" = "1" ]; then
sprache="de"
echo $sprache > lang.conf
break
elif [ "$ehcarps" = "2" ]; then
sprache="en"
echo $sprache > lang.conf
break
fi
done ;;
[eE]|[qQ])
exit ;;
esac
done
Das Einstellen der Sprache erfolgt durch das Auslesen der Konfiguration und das Belegen der Variable sprache. Deren Wert ändern Sie in den Zeilen 35 oder 39. Den neuen Inhalt von lang.conf schreiben Sie in den Zeilen 36 beziehungsweise 40. Das break danach beendet das Menü.
Mehrsprachige Eingaben erfordern den Einsatz eines Case-Konstrukts. Damit bleibt das Skript kompakt und gut zu verstehen. In der Praxis würden Sie die Texte für die Menüs nicht unbedingt in den Shell-Code aufnehmen, sondern aus einer Datei einlesen.
TIPP
Vermeiden Sie einen häufigen Fehler: Anweisungen im Case-Konstrukt erfordern ein doppeltes Semikolon (;;) am Ende.
Funktionen definieren
Funktionen nehmen generische Code-Teile auf, die Sie immer wieder verwenden. Sie bringen sie direkt am Anfang des Skripts unter. Bei der Wahl des Namens für die Funktion haben Sie weitgehend freie Hand. Vermeiden Sie jedoch Namen, die schon als Programm, Skript oder Variable im Einsatz sind – das führt in der Praxis nur zu Verwirrung.
Wählen Sie trotzdem einen bereits als Befehl verwendeten Namen für eine Funktion, gilt es, die Reihenfolge zu bedenken, in der die Shell diesen Namen aufruft: Zuerst sucht sie nach einer Funktion, dann nach einem eingebauten Befehl der Shell und zuletzt nach einem externen Tool.





