BASH echo

BASH echo

Beim Programmieren in der BASH bin ich heute ganz schön ins Schwitzen gekommen. Wenn man mit echo arbeitet und auch ab und zu mal ein Kommando in einer Sub-Shell ausführt, muss man einiges beachten — sonst guckt man u. U. dumm aus der Wäsche. Um das Verhalten von echo zu verdeutlichen, habe ich ein Verzeichnis testdir mit den drei Dateien a, b und c angelegt. Was man da mit echo alles erleben kann, zeigen folgende Beispiele.

$ STRING="Zeile 1\nZeile2\nStern *"
$ echo $STRING
Zeile 1\nZeile2\nStern a b c

Die Zeilenumbrüche werden nicht interpretiert, aber dafür wird der * von der BASH durch die Namen der Dateien in testdir ersetzt. Das lässt sich verhindern, indem man die Variable in Anführungszeichen packt.

$ echo "$STRING"
Zeile 1\nZeile 2\nStern *

Super Sache! Sollen Escape-Sequenzen wie ein Zeilenumbruch (\n) interpretiert werden, so ruft man echo einfach mit dem Schalter -e auf:

$ echo -e $STRING
Zeile 1
Zeile 2
Stern a b c

Hoppla! Der * wurde wieder durch die Dateinamen ersetzt. Also schnell die Variable in " gepackt und den Aufruf wiederholt:

$ echo -e "$STRING"
Zeile 1
Zeile 2
Stern *

Soweit so gut, alles kein Problem. Verrückt kanns werden, wenn man die Ausgabe eines Sub-Shell-Aufrufs ausgibt:

$ echo $(echo $STRING)
Zeile 1\nZeile 2\nStern a b c

Das innere echo expandiert den *, so dass die Dateinamen zu sehen sind. Das äußere echo schreibt den String auf die Ausgabe.

$ echo $(echo "$STRING")
Zeile 1\nZeile 2\nStern a b c

Die gleiche Ausgabe wie weiter oben, nur diesmal expandiert das äußere echo den *. Was tun? Wir packen den Sub-Shell-Aufruf einfach in Anführungszeichen:

$ echo "$(echo "$STRING")"
Zeile 1\nZeile 2\nStern *

Mit dem Schalter -e werden die beiden Zeilenumbrüche interpretiert. Dabei spielt es keine Rolle, ob man das -e zum inneren, äußeren oder zu beiden echo-Aufrufen hinzufügt.

$ echo "$(echo -e "$STRING")"
Zeile 1
Zeile 2
Stern *
$ echo -e "$(echo "$STRING")"
Zeile 1
Zeile 2
Stern *
$ echo -e "$(echo -e "$STRING")"
Zeile 1
Zeile 2
Stern *

Das ganze funktioniert natürlich nur, da Anführungszeichen verwendet werden. Innerhalb dieser wird nichts expandiert und auch die Escape-Sequenzen bleiben erhalten.

Mal sehen was passiert, wenn man das eine oder andere Paar " weglässt.

$ echo -e $(echo -e "$STRING")
Zeile 1 Zeile 2 a b c

Das innere echo expandiert nichts, interpretiert dafür aber die Zeilenumbrüche. Diese gehen jedoch verloren, da der Sub-Shell-Aufruf nicht in Anführungszeichen gesetzt wurde. Der Schalter -e des äußeren echo ist daher überflüssig.

$ echo $(echo -e "$STRING")
Zeile 1 Zeile 2 a b c

Ein anderes Beispiel:

$ echo -e "$(echo -e $STRING)"
Zeile 1
Zeile 2
a b c

Das innere echo expandiert den * und interpretiert die Zeilenumbrüche. Das äußere echo reicht das Ergebnis nur durch. Auch hier ist der Schalter -e überflüssig.

$ echo "$(echo -e $STRING)"
Zeile 1
Zeile 2
a b c

Viel Spaß bei der Shell-Programmierung!