Der alte Rat bestand früher darin, jeden Ausdruck mit einem doppelten Anführungszeichen zu versehen $VARIABLE
, zumindest wenn man wollte, dass er von der Shell als ein einzelnes Element interpretiert wird, da sonst Leerzeichen im Inhalt von $VARIABLE
die Shell abwerfen würden.
Ich verstehe jedoch, dass in neueren Versionen von Shells nicht mehr immer doppelte Anführungszeichen erforderlich sind (zumindest für den oben beschriebenen Zweck). Zum Beispiel in bash
:
% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory
In zsh
, auf der anderen Seite die gleichen drei Befehle folgen. Basierend auf diesem Experiment scheint es daher, dass man in diesen Fällen bash
die doppelten Anführungszeichen weglassen kann [[ ... ]]
, aber weder innerhalb [ ... ]
noch in Befehlszeilenargumenten, während zsh
in diesen Fällen die doppelten Anführungszeichen weggelassen werden können.
Aber aus Anekdotenbeispielen wie den obigen allgemeine Regeln abzuleiten, ist ein Zufallsprinzip. Es wäre schön, eine Zusammenfassung darüber zu sehen, wann doppelte Anführungszeichen erforderlich sind. Ich bin in erster Linie interessiert an zsh
, bash
und /bin/sh
.
SH_WORD_SPLIT
Option beeinflusst.Antworten:
Zuerst trenne zsh vom Rest. Es geht nicht um alte oder moderne Shells: zsh verhält sich anders. Die zsh-Designer haben beschlossen, es mit herkömmlichen Shells (Bourne, ksh, bash) nicht kompatibel zu machen, aber einfacher zu verwenden.
Zweitens ist es viel einfacher, immer doppelte Anführungszeichen zu verwenden, als sich zu merken, wann sie benötigt werden. Sie werden die meiste Zeit benötigt, daher müssen Sie lernen, wann sie nicht benötigt werden und wann sie nicht benötigt werden.
Kurz gesagt, sind doppelte Anführungszeichen immer dann erforderlich, wenn eine Liste von Wörtern oder Mustern erwartet wird . Sie sind in Kontexten optional, in denen der Parser eine Rohzeichenfolge erwartet.
Was passiert ohne Anführungszeichen?
Beachten Sie, dass ohne doppelte Anführungszeichen zwei Dinge passieren.
${foo}
oder die Ausgabe des Befehls für eine Befehlssubstitution wie$(foo)
) in Wörter aufgeteilt, wo immer Leerzeichen enthalten sind.Genauer gesagt wird das Ergebnis der Erweiterung auf jedes Zeichen aufgeteilt, das im Wert der
IFS
Variablen erscheint (Trennzeichen). Wenn eine Folge von Trennzeichen Leerzeichen (Leerzeichen, Tabulatoren oder Zeilenumbrüche) enthält, wird das Leerzeichen als einzelnes Zeichen gezählt. Führende, nachfolgende oder wiederholte Nicht-Leerzeichen-Trennzeichen führen zu leeren Feldern. Zum Beispiel mitIFS=" :"
,:one::two : three: :four
produziert leere Felder vorone
, zwischenone
undtwo
und (einem einzigen) , die zwischenthree
undfour
.\[*?
. Wenn dieses Muster mit einem oder mehreren Dateinamen übereinstimmt, wird das Muster durch die Liste der übereinstimmenden Dateinamen ersetzt.Eine nicht in Anführungszeichen gesetzte Variablenerweiterung
$foo
wird umgangssprachlich als "split + glob-Operator" bezeichnet, im Gegensatz dazu wird"$foo"
nur der Wert der Variablen verwendetfoo
. Gleiches gilt für die Befehlsersetzung:"$(foo)"
Ist eine Befehlsersetzung,$(foo)
ist eine Befehlsersetzung, gefolgt von split + glob.Wo Sie die doppelten Anführungszeichen weglassen können
Hier sind alle Fälle, die mir in einer Bourne-artigen Shell einfallen, in der Sie eine Variable oder eine Befehlsersetzung ohne doppelte Anführungszeichen schreiben können und der Wert wörtlich interpretiert wird.
Auf der rechten Seite einer Aufgabe.
Beachten Sie, dass Sie die doppelten Anführungszeichen nach benötigen
export
, da es sich um ein gewöhnliches integriertes Schlüsselwort handelt, nicht um ein Schlüsselwort. Dies gilt nur für einige Shells wie dash, zsh (in sh emulation), yash oder posh. Bash und Ksh behandeln beideexport
speziell.In einer
case
Erklärung.Beachten Sie, dass Sie in einem Fallmuster doppelte Anführungszeichen benötigen. Die Wortteilung findet in einem Fallmuster nicht statt, aber eine nicht in Anführungszeichen gesetzte Variable wird als Muster interpretiert, während eine in Anführungszeichen gesetzte Variable als Literalzeichenfolge interpretiert wird.
In doppelten Klammern. Doppelte Klammern sind Shell-Spezialsyntax.
Außer dass Sie doppelte Anführungszeichen benötigen, wenn ein Muster oder ein regulärer Ausdruck erwartet wird: auf der rechten Seite von
=
oder==
oder!=
oder=~
.Sie benötigen wie gewohnt doppelte Anführungszeichen in einfachen Klammern,
[ … ]
da es sich um eine gewöhnliche Shell-Syntax handelt (es handelt sich um einen Befehl, der zufällig aufgerufen wird[
). Siehe Einzel- oder DoppelklammernIn einer Umleitung in nicht interaktiven POSIX-Shells (weder
bash
nochksh88
).Bei einigen interaktiven Shells wird der Wert der Variablen als Platzhaltermuster behandelt. POSIX verbietet dieses Verhalten in nicht interaktiven Shells, aber einige Shells, einschließlich bash (außer im POSIX-Modus) und ksh88 (auch wenn sie als (angeblich) POSIX
sh
einiger kommerzieller Unices wie Solaris gefunden wurden), tun es dort noch (bash
versuchen auch, sie zu teilen) und die Umleitung schlägt fehl, es sei denn, das Aufteilen + Verschieben ergibt genau ein Wort. Aus diesem Grund ist es besser, Umleitungsziele in einemsh
Skript anzugeben, falls Sie es einesbash
Tages in ein Skript konvertieren oder es auf einem System ausführen möchten, auf dem es sichsh
befindet nicht konform zu diesem Punkt, oder es kann sein sourced von interaktiven Shells.Innerhalb eines arithmetischen Ausdrucks. Tatsächlich müssen Sie die Anführungszeichen weglassen, damit eine Variable als arithmetischer Ausdruck analysiert wird.
Sie benötigen jedoch die Anführungszeichen um die arithmetische Erweiterung, da sie in den meisten Shells der Wortteilung unterliegen, wie es POSIX erfordert (!?).
In einem assoziativen Array-Index.
Eine nicht in Anführungszeichen gesetzte Variable und eine Befehlsersetzung können in einigen seltenen Fällen hilfreich sein:
$IFS
wurde das nicht geändert, und Sie möchten es in Leerzeichen aufteilen.set -f
, stellen SieIFS
das Trennzeichen ein (oder lassen Sie es in Leerzeichen aufteilen), und führen Sie dann die Erweiterung durch.Zsh
In zsh können Sie mit wenigen Ausnahmen die doppelten Anführungszeichen meistens weglassen.
$var
Wird nie auf mehrere Wörter erweitert, wird jedoch auf die leere Liste erweitert (im Gegensatz zu einer Liste, die ein einzelnes, leeres Wort enthält), wenn der Wert vonvar
die leere Zeichenfolge ist. Kontrast:"${array[@]}"
Erweitert auf ähnliche Weise alle Elemente des Arrays, während$array
nur die nicht leeren Elemente erweitert werden.Die
@
Parameter Expansion Flag erfordert manchmal doppelte Anführungszeichen um die ganze Substitution:"${(@)foo}"
.Bei der Ersetzung von Befehlen wird das Feld geteilt, wenn keine Anführungszeichen gesetzt sind:
echo $(echo 'a'; echo '*')
printsa *
(mit einem einzelnen Leerzeichen), währendecho "$(echo 'a'; echo '*')"
die nicht geänderte zweizeilige Zeichenfolge gedruckt wird. Verwenden Sie"$(somecommand)"
diese Option, um die Ausgabe des Befehls in einem Wort ohne abschließende Zeilenumbrüche zu erhalten. Verwenden Sie"${$(somecommand; echo _)%?}"
diese Option, um die genaue Ausgabe des Befehls einschließlich der letzten Zeilenumbrüche abzurufen. Verwenden Sie"${(@f)$(somecommand)}"
diese Option , um ein Array von Zeilen aus der Ausgabe des Befehls abzurufen.quelle
echo "$(("$expr"))"
man bash
sagt aus: Der Ausdruck wird so behandelt, als befände er sich in doppelten Anführungszeichen, ein doppeltes Anführungszeichen in Klammern wird jedoch nicht speziell behandelt.echo
. Es könnte sich lohnen, die Sprache noch deutlicher zu machen ("Wenn der Parser eine rohe Zeichenfolge erwartet", vielleicht?)