bash-Horror: Leerzeichen in Kommandozeilen-Argumenten

Die Bourne Again SHell, oder bash, ist ja wirklich eine gute Shell, aber es in manchen Dingen ist die Syntax, bzw. die Semantik dahinter, einfach nur fragwürdig. Mein Problem: Die Übergabe von einer variablen Anzahl von Kommandozeilenargumente, die Leerzeichen enthalten dürfen.

Das Problem

Ein bash-Script soll Kommandozeilenargumente an ein anderes Programm oder Script übergeben. Die Anzahl der Kommandozeilenargumente kann variieren und einzelne Argumente können Leerzeichen enthalten.

bash-Scripte können auf die Liste der Kommandozeilenargumente mittels $@ zugreifen. Hier ist ein kleines bash-Script print-args.sh, welches alle übergebenen Kommandozeilenargumente der Reihe nach ausgibt:

#!/bin/bash

while [ "$#" != "0" ]
do
  echo "arg: $1"
  shift
done

bash splittet die Kommandozeile an Leerzeichen. Alles nach dem Programm wird als Liste von Kommandozeilenargumenten an das Programm übergeben:

$ ./print-args.sh alpha bravo charle
arg: alpha
arg: bravo
arg: charlie

Um Leerzeichen zu erhalten können diese entweder escaped oder der Text in Anführungszeichen (einfach oder doppelt) gesetzt werden:

$ ./print-args.sh "alpha bravo" charle
arg: alpha bravo
arg: charlie

Die gleiche Ausgabe gibt es für

$ ./print-args.sh 'alpha bravo' charle

und

$ ./print-args.sh alpha\ bravo charle

Soweit ist alles in Ordnung. Ein anderes bash-Script pass-args.sh soll jedoch die Kommandozeilenargumente, die es erhalten hat, an dieses Script weitergeben:

$ ./pass-args.sh alpha bravo charle
arg: alpha
arg: bravo
arg: charlie

Auch soweit ist noch alles in Ordnung. Jetzt soll aber ein Leerzeichen erhalten bleiben:

$ ./pass-args.sh "alpha bravo" charle
arg: alpha
arg: bravo
arg: charlie

Obwohl das Leerzeichen in Anführungszeichen steht werden drei Kommandozeilenargumente ausgegeben.

Die Ursache

Grund für die Ausgabe von drei statt zwei Argumenten ist die Art und Weise, wie bash Programme aufruft. Zuerst bildet es eine Kommandozeile indem es in der Zeile alle Variablen ersetzt. Es wird also intern eine Kommandozeile

./print-args.sh alpha bravo charlie

gebildet. Die umschließenden Anführungszeichen bzw. das Escape-Zeichen verschwinden praktisch, weil diese nur für die Bestimmung der Kommandozeilenargumente von pass-args.sh erforderlich waren. print-args.sh sieht somit wieder drei Argumente.

Die Lösung

Die Lösung ist so einfach wie unintuitiv: $@ muß einfach in doppelte Anführungszeichen gesetzt werden. (Hinweis. Bei einfachen Anführungszeichen erfolgt keine Variablen-Expansion.):

#!/bin/bash

./print-args.sh "$@"

Die Lösung ist nicht intuitiv, da hier die Verwendung der Anführungszeichen eine andere Wirkung haben. Eigentlich würde man für das obige Beispiel eine Kommandozeile der Form

./print-args.sh "alpha bravo charlie"

erwarten. Damit würde das Script genau ein Argument bekommen. Tatsächlich wird jedoch eine Kommandozeile der Form

./print-args.sh "alpha bravo" "charlie"

erzeugt.

oppol.abryok+blog-My4yMy4xMjguMjQ1@gmail.com