Open Source im professionellen Einsatz

Shellskripte aus der Stümper-Liga - Folge 6: Gleich ist nicht gleich Gleich-Gleich

Bash Bashing

Bedingungen in Bash-Skripten sind zwar ziemlich durchdacht, aber gleichzeitig so trickreich, dass sie selbst manchen Profi in die Falle locken. Dazu kommt, dass sich das Prinzip auch bis zur Erschöpfung beugen lässt. Als abschreckendes Beispiel hält diesmal Knoppix her.

Die If-Verzweigung der Bash erweist sich im Folgenden als stilles Wasser. Dem eiligen Betrachter erscheint sie als ganz unschuldige Verzweigung wie in vielen anderen Programmiersprachen auch. Erst genaueres Hinschauen offenbart die Abgründe. So denken die meisten Gelegenheits-Basher, dass die eckigen Klammern Ausdruck des Stilempfindens von Stephen R. Bourne waren, dem ursprünglichen Entwickler der Ur-Shell [1].

Das stimmt aber nur teilweise. Genau genommen sind die eckigen Klammern nämlich gar kein Teil der Shellsyntax. Hinter dem Schlüsselwort »if« erwartet sie nämlich einfach ein Kommando bis zum nächsten Semikolon oder alternativ dem nächsten Zeilenumbruch. Dieses Kommando führt die Shell aus und betrachtet anschließend den Rückgabewert, den jeder Unix-Prozess liefert, wenn er terminiert (diesen Wert rufen Bash-Anwender mit »echo $?« ab). Abhängig vom Wert führt der Kommandointerpreter entweder den Code im Then- oder Else-Zweig aus (siehe Abbildung 1).

Abbildung 1: Die Shellvariable »$?« speichert den Erfolg des letzten Kommandos. Steht sie auf 0, lief alles glatt. Grep setzt sie auf 1, falls es den Suchbegriff nicht finden konnte, und auf 2, falls die gesuchte Datei nicht vorhanden ist.

Abbildung 1: Die Shellvariable »$?« speichert den Erfolg des letzten Kommandos. Steht sie auf 0, lief alles glatt. Grep setzt sie auf 1, falls es den Suchbegriff nicht finden konnte, und auf 2, falls die gesuchte Datei nicht vorhanden ist.

Für Einsteiger mit C-Vorkenntnissen ist verwirrend, dass hier quasi eine umgekehrte Logik gilt: Terminiert ein Prozess fehlerfrei, gibt er den Wert 0 zurück. Mit jedem anderen Wert signalisiert er seinem Elternprozess, dass irgendein Problem aufgetreten ist. Konnte das Kommando den Suchbegriff nicht finden, meldet der Aufruf 1 zurück, gibt es die zu durchsuchende Datei gar nicht, lautet die Antwort des Prozesses 2. Aus diesem Grund lässt sich ein Check, ob eine Datei einen bestimmten String enthält, sehr kurz notieren:

if grep -q "Ubuntu" /etc/issue; then
    echo "Dies ist ein (K)Ubuntu!"
fi

Die Option »-q« nutzt Grep, da das Kommando weiter Ausgaben erzeugt, die jedoch zwischen die Statusmeldung geraten. Mit der Einstellung unterdrückt das Tool die Ausgabe und bricht darüber hinaus nach dem ersten Treffer ab.

Tückischer Testfall

Das Beispiel zeigt, dass If einzig ausgewertete Boolsche Ausdrücke zur Entscheidung heranzieht. Um aber auch Prädikate auf numerischen Werten oder Dateien anzubieten, musste ein eigenes Kommando her: Das Programm zum Testen auf diese Eigenschaften nannten seine Entwickler stimmigerweise »test«. Dieser Umstand ist zwar genau genommen kein Bash-Problem, aber dennoch tappt wohl jeder Unix-Anwender einmal im Leben in die in Abbildung 2 gezeigte Falle und schreibt ein eigenes Test-Programm.

Obwohl der kurze Quelltext eingetippt und fehlerfrei übersetzt ist, erzeugt das Programm scheinbar keine Ausgabe. Selbst das aktuelle Verzeichnis ist - korrekterweise am Ende - im Pfad. Auflösung gibt die letzte Zeile in Abbildung 2: Im Verzeichnis »/usr/bin« gibt es schon ein Programm gleichen Namens. Es bleibt der dringende Aufruf, Testprogramme niemals »test« zu nennen und außerdem solche Tools und Skripte explizit zu beginnen, wie in »./demo«. Dann dürfen Poweruser sogar den abschließenden Punkt aus ihrem Pfad entfernen.

Abbildung 2: Beliebte Falle: Ein selbst geschriebenes Hallo-Welt-Programm erzeugt keine Ausgabe. Der Grund ist weder ein Programm- noch ein Übersetzungs- oder Pfadfehler, sondern die Tatsache, dass es in einem anderen Verzeichnis schon ein gleichnamiges Programm »test« gibt.

Abbildung 2: Beliebte Falle: Ein selbst geschriebenes Hallo-Welt-Programm erzeugt keine Ausgabe. Der Grund ist weder ein Programm- noch ein Übersetzungs- oder Pfadfehler, sondern die Tatsache, dass es in einem anderen Verzeichnis schon ein gleichnamiges Programm »test« gibt.

Gleicher als die anderen

Da »if test Argumente« sperrig zu notieren ist, haben Entwickler dem Tool den Alias »[« spendiert. Wer ganz genau hinschaut, stellt in Abbildung 3 fest, dass es doch Unterschiede gibt: Die schließende Klammer. Vermutlich hatte einer der Programmierer die Sorge, dass die Welt ohne sie aus den Fugen gerät. Beide Kommandos verstehen nun aber eine Vielzahl von Testprädikaten, etwa »-d Pfad« wie in Abbildung 3, das prüft, ob der angegebene Pfad auch existiert. Problematisch wird es beim Test auf Gleichheit:

Abbildung 3: Es gibt kleine Unterschiede zwischen »[« und »test«: Trotz gleicher Funktion der beiden Tools unterscheidet sie die schließende Klammer. Der Returncode zeigt an, ob es sich bei dem Pfad um ein Verzeichnis handelt.

Abbildung 3: Es gibt kleine Unterschiede zwischen »[« und »test«: Trotz gleicher Funktion der beiden Tools unterscheidet sie die schließende Klammer. Der Returncode zeigt an, ob es sich bei dem Pfad um ein Verzeichnis handelt.

if [ 0 = 0 ]; then echo "gleich!"; fi

besteht im Gegensatz zu

if [ 0 = 00 ]; then echo "gleich!"; fi

die Prüfung, was den Unterschied von Datentypen anschaulich vor Augen führt. Das liegt daran, dass »=« auf Strings operiert. Um zwei numerische Werte zu vergleichen, wäre »-eq« für die Gleichheit, »-lt« für kleiner als und »-gt« für größer als die bessere Wahl. Letztere sind auch nötig, da »<« und »>« ja schon andere Bedeutungen bei der Ein- und Ausgabeumlenkung haben.

Um ein vertracktes Thema noch verwirrender zu machen, sind einige Shells beim Stringvergleich nachgiebiger als andere. Das Bash-Builtin »test« akzeptiert beispielsweise zusätzlich auch »==« als Vergleichsoperator, Posix hingegen fordert nur das einzelne Gleichheitszeichen, wie Bash-Bashing-Leser Kester Habermann per E-Mail anmerkt.

Diesen Artikel als PDF kaufen

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook