![]() |
|
||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
|
||
|
TFT Monitor bei
Mercateo kaufen.
Neues Netbook? Ein Preisvergleich lohnt sich. Bei uns finden sie Notebooks, PDAs und Drucker mit Testberichten und Tipps. Diamant Buchhaltungssoftware – transparent und detailliert auch für die Konzernbuchhaltung. Günstige Shareware Programme als direkte Downloads im Software Portal. Bis zu 70% sparen durch Preisvergleich. |
||
|
von Mirko Dölle
Unter Kontrollstrukturen versteht man allgemein Sprachkonstrukte -- sagen wir einfach einmal Befehle --, mit denen sich die Ausführung von Programmteilen steuern lässt. Die wohl bekannteste Kontrollstruktur ist if, die Prüfung einer Bedingung. Sie hat in der Bash die Form:
if Bedingung1; then <I>Wenn Bedingung 1 wahr<I> elif Bedingung2; then <I>Wenn Bedingung 2 wahr<I> elif Bedingung3; then <I>Wenn Bedingung 3 wahr<I> else <I>Wenn Bedingung 1 bis 3 falsch<I> fi
Die Konstruktion beginnt stets mit dem Schlüsselwort if und endet mit fi, dem umgedrehten "if". Das Konzept des if-Konstrukts ist modular: Was nicht gebraucht wird, kann entfallen. Wenn Sie also nur sagen wollen, dass die Variablen A und B das gleiche enthalten, können Sie schreiben:
if [ $A = $B ]; then echo "A und B sind gleich." fi
Wenn Sie im Falle eines Unterschieds dies ebenfalls vermelden wollen, kommt zusätzlich else ins Spiel:
if [ $A = $B ]; then echo "A und B sind gleich." else echo "A und B sind ungleich." fi
Im letzten Beispiel hatten wir zwei Anweisungsblöcke, den if-Block und den else-Block, mit je einer echo-Anweisung. Diese Blöcke können auch mehrere Befehle enthalten:
if [ $A = $B ]; then echo "A und B sind gleich." echo "Wer hätte das gedacht?" else echo "A und B sind ungleich." echo "Schade eigentlich." fi
Die beiden Blöcke reichen vom Schlüsselwort then beziehungsweise else bis zum nächsten Schlüsselwort des if-Konstrukts. Dabei sind auch Verschachtelungen möglich:
if [ $A = $B ]; then
echo "A und B sind gleich."
if [ $A = "0" ]; then
echo "A und B sind null."
fi
else
echo "A und B sind ungleich."
fi
In diesem Fall wird das innere if-Konstrukt als eine einzige Anweisung betrachtet und könnte wiederum weitere if-Konstrukte enthalten.
if kann nur zwei Zustände unterscheiden: Wahr oder falsch, wobei 0 als wahr und alles andere als falsch gewertet wird. Die Bedingung wird dabei als Programmaufruf aufgefasst:
if echo "Hallo Welt"; then echo "OK" fi
Die Bedingung im letzten Beispiel ist echo "Hallo Welt" -- und obwohl wir keinerlei Vergleich haben, scheint die Bedingung wahr zu sein, denn es wird anschließend OK ausgegeben. Das Ergebnis des echo-Aufrufs muss 0 gewesen sein. Das können Sie mit der Spezial-Variablen $? überprüfen, die wir in Teil 2 (Ausgabe 01/2001) angerissen haben:
<B>echo "Hallo Welt"<B> Hallo Welt <B>echo $?<B> 0
$? liefert Ihnen den Rückgabewert (Exit-Status), den jedes Programm beim Beenden an das Betriebssystem zurückgeben muss. Unter den Programmierern hat sich eingebürgert, bei normalem Programmablauf stellvertretend 0 zurückzugeben, im Fehlerfall dann einen anderen Wert. Es gibt allerdings auch einzelne Programme, die nur negative Werte für aufgetretene Fehler liefern. Informationen, welcher Wert was bedeutet, findet man manchmal in der Dokumentation oder Manual-Page.
Anwender benötigen den Rückgabewert normalerweise nicht, wohl aber Skripte. In der Praxis kommt man nicht immer mit dem Sprachumfang der Bash aus, man bedient sich externer Programme wie cp, cat oder grep, um einzelne Aufgaben zu lösen. Mit dem Exit-Status kann das Bash-Skript sehr leicht entscheiden, ob bei einem der Kommandos ein Fehler aufgetreten ist oder nicht -- und das, ohne die Bildschirmausgabe auswerten oder den Anwender fragen zu müssen.
Als Beispiel verwenden wir das Filter-Programm grep. Damit kann man Dateien nach dem Vorkommen von Wörtern und anderen Zeichenfolgen durchsuchen. Normal gibt grep das Ergebnis direkt auf dem Bildschirm aus, mit der Option "-q" im folgenden Listing unterdrücken wir das jedoch. Wir lassen die Datei /etc/passwd nach dem nicht existenten Benutzer tux durchsuchen:
if grep -q tux /etc/passwd; then echo "Hallo Tux." else echo "Tux kenne ich nicht." fi
Das Ergebnis ist "Tux kenne ich nicht." Mit dem als root aufzurufenden Befehl useradd tux können Sie nun den Benutzer tux anlegen -- keine Sorge, es kann sich niemand als Tux einloggen. Unser Beispiel liefert nun "Hallo Tux." Mit userdel tux löschen Sie Tux später wieder.
Wir haben ausgenutzt, dass grep im Erfolgsfall, wenn es die Zeichenkette "tux" finden konnte, 0 zurückgibt, während der Rückgabewert bei Misserfolg 1 ist.
Die Länge der Bedingung ist nicht beschränkt, sie kann mehrere Programmaufrufe umfassen. Bewertet wird dabei stets der Rückgabewert des letzten Kommandos. Zur besseren Lesbarkeit benutzt man für mehrzeilige Bedingungen eine etwas andere Schreibweise des if-Konstrukts:
01 if 02 echo "Suche:" 03 echo " tux" 04 echo "in" 05 echo "/etc/passwd." 06 grep -q tux /etc/passwd; 07 then 08 echo "Hallo Tux." 09 else 10 echo "Tux kenne ich nicht." 11 fi
Wichtig ist das Semikolon hinter der letzten Anweisung im Bedingungs-Teil, ohne das das Schlüsselwort then nicht erkannt würde. Der Einsatz mehrzeiliger Bedingungs-Blöcke ist jedoch die Ausnahme und nur selten sinnvoll.
Das im Bedingungs-Teil wohl am häufigsten benutzte Programm ist test. Hierbei handelt es sich um ein Hilfsmittel, mit dem umfangreiche Bedingungen aufgebaut werden können. Das Ergebnis von test ist wahr oder falsch.
if test $A = $B; then echo "A und B sind gleich." fi
Wie Sie vielleicht merken, haben wir Ihnen test gleich im ersten Beispiel untergeschoben, und zwar in der Kurzschreibweise als [ ]. Tatsächlich sind die eckigen Klammern ein Synonym (Alias) von test, das in der Bash definiert ist. In Tabelle 1 finden Sie eine Liste aller Parameter, die Sie im Zusammenhang mit test verwenden können.
| Tabelle 1: Die Optionen von test | |
| Eigenschaften von Dateien | |
| -e Datei | wahr, wenn Datei existiert |
| -r Datei | wahr, wenn Datei existiert und lesbar ist |
| -w Datei | wahr, wenn Datei existiert und beschreibbar ist |
| -x Datei | wahr, wenn Datei existiert und ausführbar ist |
| -s Datei | wahr, wenn Datei existiert und länger als null Bytes ist |
| Datei1 -nt Datei2 | wahr, wenn Datei1 neuer ist als Datei2 |
| Datei1 -ot Datei2 | wahr, wenn Datei1 älter ist als Datei2 |
| Datei1 -ef Datei2 | wahr, wenn Datei1 und Datei2 ein und die selbe Datei sind (Hard-Link) |
| -O Datei | wahr, wenn Datei existiert und dem aktuellen Benutzer gehört |
| -G Datei | wahr, wenn Datei existiert und der Gruppe des aktuellen Benutzers gehört |
| -f Datei | wahr, wenn Datei existiert und eine normale Datei ist |
| -d Datei | wahr, wenn Datei ein Verzeichnis ist |
| -L Datei | wahr, wenn Datei existiert und ein symbolischer Link ist |
| -b Datei | wahr, wenn Datei ein Block-Device ist |
| -c Datei | wahr, wenn Datei ein Character-Device ist |
| -p Datei | wahr, wenn Datei existiert und eine Pipe ist |
| -S Datei | wahr, wenn Datei existiert und ein Socket ist |
| -t fd | wahr, wenn fd ein auf einem Terminal geöffneter Dateibezeichner ist |
| -u Datei | wahr, wenn Datei existiert und das SUID-Bit gesetzt ist |
| -g Datei | wahr, wenn Datei existiert und das SGID-Bit gesetzt ist |
| -k Datei | wahr, wenn Datei existiert und das Sticky-Bit gesetzt ist |
| Verkettung von Bedingungen | |
| ! Bedingung | wahr, wenn Bedingung falsch ist, und umgekehrt |
| Bedingung1 -a Bedingung2 | wahr, wenn beide Bedingungen wahr sind |
| Bedingung1 -o Bedingung2 | wahr, wenn eine der beiden Bedingungen wahr ist |
| Vergleich von Zeichenketten | |
| String1 = String2 | wahr, wenn String1 und String2 gleich sind |
| String1 == String2 | wie String1 = String2 |
| String1 != String2 | wahr, wenn String1 und String2 nicht gleich sind |
| String1 < String2 | wahr, wenn String1 alphabetisch vor String2 eingeordnet wird |
| String1 > String2 | wahr, wenn String1 alphabetisch hinter String2 eingeordnet wird |
| -z String | wahr, wenn String die Länge null hat |
| -n String | wahr, wenn String länger als null Zeichen ist. |
| String | wie -n String |
| Vergleich von Zahlenwerten | |
| Wert1 -eq Wert2 | wahr, wenn Wert1 und Wert2 arithmetisch gleich sind |
| Wert1 -ne Wert2 | wahr, wenn Wert1 und Wert2 arithmetisch ungleich sind |
| Wert1 -lt Wert2 | wahr, wenn Wert1 arithmetisch kleiner als Wert2 ist |
| Wert1 -le Wert2 | wahr, wenn Wert1 arithmetisch kleiner oder gleich Wert2 ist |
| Wert1 -gt Wert2 | wahr, wenn Wert1 arithmetisch größer als Wert2 ist |
| Wert1 -ge Wert2 | wahr, wenn Wert1 arithmetisch größer oder gleich Wert2 ist |
| Bash-Optionen | |
| -o Option | wahr, wenn die Bash-Option Option eingeschaltet ist |
Im nächsten Beispiel nutzen wir die Option -r von test, um erst das Vorhandensein der /etc/passwd festzustellen, bevor wir nach dem Benutzer tux suchen:
if [ -r /etc/passwd ]; then
if grep -q tux /etc/passwd; then
echo "Hallo Tux."
else
echo "Tux kenne ich nicht."
fi
else
echo "/etc/passwd nicht lesbar."
fi
Wichtig ist, dass Sie bei Verwendung der Klammern als Kurzschreibweise für test ein Leerzeichen zwischen Klammer und erster Option lassen, sonst erkennt die Bash das Kürzel nicht. Der Parameter "-r" prüft, ob es die Datei /etc/passwd gibt und ob sie lesbar ist. Wenn wir uns zudem vergewissern wollten, dass es sich bei /etc/passwd um eine reguläre Datei und nicht etwa um einen symbolischen Link handelt, müssen wir die Bedingung erweitern:
if [ -r /etc/passwd <B>-a<B> -f /etc/passwd ]; then
if grep -q tux /etc/passwd; then
echo "Hallo Tux."
else
echo "Tux kenne ich nicht."
fi
else
echo "/etc/passwd nicht lesbar oder nicht regulär."
fi
Die im Listing hervorgehobene Option "-a" bewirkt, dass beide Bedingungen getestet und mit einem "logischen Und" verknüpft werden. Sind beide wahr, ist das Ergebnis wahr -- ist mindestens eine falsch, ist auch das Ergebnis falsch. Anders verhält sich das "logische Oder", bei test die Option "-o". Hier genügt eine wahre Bedingung, damit das Gesamtergebnis wahr wird. "-o" und "-a" können mehrfach vorkommen. Es werden dann von links nach rechts zunächst alle "Und"-Verknüpfungen und dann alle "Oder"-Verknüpfungen ausgewertet.
Doch der logischen Verknüpfung mittels test sind Grenzen gesetzt. So ist es zum Beispiel nicht möglich, die Prüfung der /etc/passwd zusammen mit der Suche nach dem Benutzer tux durchzuführen. Hier müssen wir uns der logischen Operatoren && (Und) und || (Oder) aus der Bash bedienen, die wir im ersten Teil (LinuxUser 12/2000, S. 38ff) in Tabelle 2 vorgestellt haben:
if [ -r /etc/passwd ] && grep -q tux /etc/passwd; then echo "Hallo Tux." else echo "Tux kenne ich nicht." fi
Einziger Nachteil dieser Lösung: Ist /etc/passwd nicht lesbar, erhalten wir die Meldung, den User tux gäbe es nicht. Wie auch im Beispiel der Option "-o" bei test lassen sich die logischen Operatoren der Bash mehrfach hintereinander benutzen und werden ebenfalls von links nach rechts ausgewertet.
Damit endet der vierte Teil des Programming Corners. In der nächsten Ausgabe wird uns das Thema Kontrollstrukturen weiter beschäftigen, insbesondere mit der Fallunterscheidung mittels case sowie den ersten Schleifen. (mdö)
© Copyright 1999-2001 Linux New Media AG
Dieser Online-Artikel kann Links enthalten, die auf nicht mehr vorhandene Seiten verweisen. Wir ändern solche "broken links" nur in wenigen Ausnahmefällen. Der Online-Artikel soll möglichst unverändert der gedruckten Fassung entsprechen.
Druckerfreundliche Version |
Feedback zu dieser Seite
|
Datenschutz |
© 2010 Linux New Media AG
[Linux-Magazin]
[LinuxUser]
[EasyLinux]
[Linux-Community]
[Ubuntu User]
[Linux Technical Review]
[Linux Magazine]
[Linux Pro Magazine]
[Ubuntu User]
[EasyLinux Poland]
[Linux Magazine Poland]
[Linux Magazine Brasil]
[EasyLinux Brasil]
[Linux Magazine Spain]