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.
- Zunächst wird das Ergebnis der Erweiterung (der Wert der Variablen für eine Parametersubstitution wie
${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 mit IFS=" :"
, :one::two : three: :four
produziert leere Felder vor one
, zwischen one
und two
und (einem einzigen) , die zwischen three
und four
.
- Jedes Feld, das aus der Aufteilung resultiert, wird als Glob (ein Platzhaltermuster) interpretiert, wenn es eines der Zeichen enthält
\[*?
. 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 verwendet foo
. 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.
var=$stuff
a_single_star=*
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 beide export
speziell.
export VAR="$stuff"
In einer case
Erklärung.
case $var in …
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.
a_star='a*'
case $var in
"$a_star") echo "'$var' is the two characters a, *";;
$a_star) echo "'$var' begins with a";;
esac
In doppelten Klammern. Doppelte Klammern sind Shell-Spezialsyntax.
[[ -e $filename ]]
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 =~
.
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
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 Doppelklammern
In einer Umleitung in nicht interaktiven POSIX-Shells (weder bash
noch ksh88
).
echo "hello world" >$filename
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 einem sh
Skript anzugeben, falls Sie es eines bash
Tages in ein Skript konvertieren oder es auf einem System ausführen möchten, auf dem es sich sh
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.
expr=2*2
echo "$(($expr))"
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.
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
Eine nicht in Anführungszeichen gesetzte Variable und eine Befehlsersetzung können in einigen seltenen Fällen hilfreich sein:
- Wenn der Variablenwert oder die Befehlsausgabe aus einer Liste von Glob-Mustern besteht und Sie diese Muster auf die Liste der übereinstimmenden Dateien erweitern möchten.
- Wenn Sie wissen, dass der Wert kein Platzhalterzeichen enthält,
$IFS
wurde das nicht geändert, und Sie möchten es in Leerzeichen aufteilen.
- Wenn Sie einen Wert auf ein bestimmtes Zeichen aufteilen möchten: Deaktivieren Sie das Globbing mit
set -f
, stellen Sie IFS
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 von var
die leere Zeichenfolge ist. Kontrast:
var=
print -l $var foo # prints just foo
print -l "$var" foo # prints an empty line, then foo
"${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 '*')
prints a *
(mit einem einzelnen Leerzeichen), während echo "$(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.
SH_WORD_SPLIT
Option beeinflusst.