Als erste Linie Java - Programmierer, finde ich die bash if
- then
Konstrukt 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
bash
shell
test
whitespace
Konrad Höffner
quelle
quelle
Antworten:
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 Namef
oder isto
". 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.
$1
bedeutet nicht "der Wert von Parameter 1": Es bedeutet "den Wert von Parameter 1 nehmen, ihn in Leerzeichen (oder was auch immer der Wert vonIFS
ist) 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: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.Es gibt jedoch eine Ausnahme: Um
[[ "$foo" = "$bar" ]]
zu testen, ob die beiden Variablen denselben Wert haben, sind doppelte Anführungszeichen erforderlich$bar
, andernfalls$bar
wird dies als Platzhaltermuster interpretiert. Anstatt sich an die Details zu erinnern, können Sie auch immer doppelte Anführungszeichen verwenden.quelle
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[-n
keine Funktion oder Binärdatei ist Bash Know (zumindest bis Sie selbst eine erstellen).Wenn schreiben Sie
[-n $1 ]
es bedeutet ,[-n
mit Argumenten$1
und]
die keinen Sinn machen ,und wenn Sie setzen
[ -n $1]
es bedeutet ,[
mit dem Argument-n
und$1]
aber das fehlende]
Argument Ihrer Funktion ,[
damit es nicht Ihren Ausdruck auswertenquelle