Als hauptsächlich Java-Programmierer finde ich die Bash if
–then
Konstrukt ziemlich verwirrend, insbesondere in Bezug auf Leerzeichen. Kann jemand erklären, warum das erste funktioniert, aber nicht das 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
Akzeptierte Antwort:
Die Inkonsistenz ist größtenteils auf historische Gründe zurückzuführen.
Die Verwendung von Klammern als bedingter Befehl kam nach der Verwendung von Klammern in Platzhaltermustern. Also zum Zeitpunkt [ -n foo ]
kam auf die Bildfläche, [foo]
bedeutete bereits „eine Datei, deren Name f
ist oder o
“. Während nur wenige Verwendungen des Klammeroperators in der Praxis mit der realistischen Verwendung der Klammern in Platzhaltern in Konflikt geraten wären, entschieden sich die Autoren, nicht das Risiko einzugehen, vorhandene Skripte durch eine Änderung der Syntax zu beschädigen. Diese Designwahl erleichterte auch die Implementierung:anfänglich [
wurde als externer Befehl implementiert, was nicht möglich gewesen wäre, wenn das Leerzeichen nach [
war optional gewesen. (Moderne Systeme haben immer noch [
als externes Kommando, aber fast alle modernen Shells haben es auch eingebaut.)
Aus ähnlichen Gründen ist Ihr „funktionierender“ Code in den meisten Fällen tatsächlich falsch. $1
bedeutet nicht „den Wert von Parameter 1“:es bedeutet „nehmen Sie den Wert von Parameter 1, teilen Sie ihn in einzelne Wörter bei Leerzeichen (oder was auch immer der Wert von IFS
ist ist) und interpretiere jedes Wort als Glob-Muster“. Um „den Wert von Parameter 1“ zu schreiben, sind doppelte Anführungszeichen erforderlich:"$1"
. Siehe Wann sind doppelte Anführungszeichen erforderlich? für das nüchterne. Sie müssen das nicht verstehen; Sie müssen sich nur daran erinnern:Setzen Sie immer doppelte Anführungszeichen um Variablenersetzungen "$foo"
und Befehlsersetzungen "$(foo)"
. Also:
if [ -n "$1" ]; then …
In bash, ksh und zsh, aber nicht in einfachem sh, können Sie auch doppelte Klammern verwenden. Einfache Klammern [ … ]
werden wie ein gewöhnlicher Befehl geparst (und tatsächlich [
ist ein gewöhnlicher Befehl, obwohl er normalerweise eingebaut ist). Doppelte Klammern sind ein separates syntaktisches Konstrukt und Sie können die doppelten Anführungszeichen meistens weglassen.
if [[ -n $1 ]]; then …
Es gibt jedoch eine Ausnahme:[[ "$foo" = "$bar" ]]
Um zu testen, ob die beiden Variablen denselben Wert haben, sind doppelte Anführungszeichen um $bar
erforderlich , andernfalls $bar
wird als Platzhaltermuster interpretiert. Auch hier können Sie, anstatt sich an die Details zu erinnern, genauso gut die ganze Zeit doppelte Anführungszeichen verwenden.