Warum sind Bash-Tests in Bezug auf Leerzeichen so wählerisch?

7

Als erste Linie Java - Programmierer, finde ich die bash if- thenKonstrukt ziemlich verwirrend, vor allem in Bezug auf Leerzeichen. Kann jemand erklären, warum der erste funktioniert, aber nicht der zweite oder dritte?

#works
if [ -n $1 ]; then echo "parameterized"; fi

#output: ./links: Zeile 1: [-n: Kommando nicht gefunden.
if [-n $1 ]; then echo "parameterized"; fi

#output: ./links: Zeile 1: [: Fehlende `]'
if [ -n $1]; then echo "parameterized"; fi
Konrad Höffner
quelle
5
Wenn Sie eine Variable nicht in Anführungszeichen setzen, wird der Operator split + glob in Shells angezeigt. Es gibt sehr wenige Fälle, in denen Sie Variablen wirklich nicht in Anführungszeichen setzen möchten.
Stéphane Chazelas

Antworten:

17

Die Inkonsistenz ist größtenteils auf historische Gründe zurückzuführen.

Die Verwendung von Klammern als bedingter Befehl erfolgte nach der Verwendung von Klammern in Platzhaltermustern. Also kam zu der Zeit schon [ -n foo ]die Szene auf, [foo]bedeutete schon "eine Datei, deren Name foder ist o". Während in der Praxis nur wenige Verwendungen des Operators "Klammern" mit realistischen Verwendungen der Klammern in Platzhaltern in Konflikt geraten wären, haben die Autoren beschlossen, nicht zu riskieren, vorhandene Skripte durch Ändern der Syntax zu beschädigen. Diese Entwurfsauswahl erleichterte auch die Implementierung: Ursprünglich [wurde sie als externer Befehl implementiert, was nicht möglich gewesen wäre, wenn der nachfolgende Speicherplatz [optional gewesen wäre. (Moderne Systeme haben immer noch [einen externen Befehl, aber fast alle modernen Shells haben ihn auch eingebaut.)

Aus ähnlichen Gründen ist Ihr "funktionierender" Code in den meisten Fällen tatsächlich falsch. $1bedeutet nicht "der Wert von Parameter 1": Es bedeutet "den Wert von Parameter 1 nehmen, ihn in Leerzeichen (oder was auch immer der Wert von IFSist) in separate Wörter aufteilen und jedes Wort als Glob-Muster interpretieren". Die Art und Weise, wie „der Wert von Parameter 1“ geschrieben wird, erfordert doppelte Anführungszeichen : "$1". Siehe Wann ist eine doppelte Anführungszeichen erforderlich? für das Wesentliche. Sie müssen das nicht verstehen; Alles, woran Sie sich erinnern müssen, ist: Setzen"$foo""$(foo)" Sie immer doppelte Anführungszeichen um Variablensubstitutionen und Befehlssubstitutionen . Somit:

if [ -n "$1" ]; then 

In bash, ksh und zsh, aber nicht in plain sh, können Sie auch doppelte Klammern verwenden. Einzelne Klammern [ … ]werden wie ein gewöhnlicher Befehl analysiert (und sind in der Tat [ein gewöhnlicher Befehl, wenn auch normalerweise eingebaut). Doppelte Klammern sind ein separates syntaktisches Konstrukt, und Sie können die doppelten Anführungszeichen die meiste Zeit weglassen.

if [[ -n $1 ]]; then 

Es gibt jedoch eine Ausnahme: Um [[ "$foo" = "$bar" ]]zu testen, ob die beiden Variablen denselben Wert haben, sind doppelte Anführungszeichen erforderlich $bar, andernfalls $barwird dies als Platzhaltermuster interpretiert. Anstatt sich an die Details zu erinnern, können Sie auch immer doppelte Anführungszeichen verwenden.

Gilles 'SO - hör auf böse zu sein'
quelle
+1 für eine nette, prägnante Erklärung des '$ 1' bedeutet nicht "der Wert von Parameter 1" - dies ist das Entscheidende, was dazu gesagt werden muss, und das Wesentliche, mit dem Sie verbunden sind, könnte tatsächlich verbessert werden Beginnen Sie mit dem, was Sie hier gesagt haben.
Don Hatch
11

Tatsächlich ist das Zeichen [ein integrierter Shell-Befehl, der das Argument auswertet, bis das Argument ]
bash ein durch Leerzeichen getrenntes Argument verwendet. Wenn Sie also aufrufen möchten, müssen [Sie ein Leerzeichen einfügen, oder es wird versucht, den Befehl auszuführen, der [-nkeine Funktion oder Binärdatei ist Bash Know (zumindest bis Sie selbst eine erstellen).

Wenn schreiben Sie [-n $1 ]es bedeutet ,
[-nmit Argumenten $1und ]die keinen Sinn machen ,
und wenn Sie setzen [ -n $1]es bedeutet ,
[mit dem Argument -nund $1]aber das fehlende ]Argument Ihrer Funktion , [damit es nicht Ihren Ausdruck auswerten

Kiwy
quelle
Hm, ich benutze es seit Jahren und habe nie daran gedacht, warum es so ist und nicht anders. Das macht total Sinn. Danke für die Ausbildung.
Marcin
@Marcin Ich habe mir die Frage oft gestellt und kürzlich eine Antwort zum Erstellen von CDs gelesen . und dann verstehe ich, warum ein Raum eine Verpflichtung war, denn ohne ihn macht es keinen Sinn: D
Trotzdem