$ VAR vs $ {VAR} und zitieren oder nicht zitieren

139

ich kann schreiben

VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"

Das Endergebnis scheint mir alle ungefähr gleich zu sein. Warum soll ich den einen oder anderen schreiben? Sind einige davon nicht portabel / POSIX?

Xenoterracid
quelle

Antworten:

99

VAR=$VAR1ist eine vereinfachte Version von VAR=${VAR1}. Es gibt Dinge, die der zweite tun kann, die der erste nicht kann, zum Beispiel einen Array-Index referenzieren (nicht portierbar) oder eine Teilzeichenfolge entfernen (POSIX-portierbar). Siehe die Mehr zu Variablen Abschnitt des Bash Leitfaden für Anfänger und Parameter Expansion in der POSIX - Spezifikation.

Die Verwendung von Anführungszeichen um eine Variable wie in rm -- "$VAR1"oder rm -- "${VAR}"ist eine gute Idee. Dies macht den Inhalt der Variablen zu einer atomaren Einheit. Wenn der Variablenwert Leerzeichen (also Zeichen in der $IFSSondervariable, standardmäßig Leerzeichen) oder Globenzeichen enthält und Sie ihn nicht in Anführungszeichen setzen, wird jedes Wort für die Generierung von Dateinamen (Globenzeichen) in Betracht gezogen, dessen Erweiterung beliebig viele Argumente liefert mache.

$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'

$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename

Zur Portabilität: Gemäß POSIX.1-2008 Abschnitt 2.6.2 sind die geschweiften Klammern optional.

Shawn J. Goff
quelle
@ Shawn hat meine Frage aktualisiert, weil ich auch neugierig auf Portabilität bin
Xenoterracide
@ Shawn: Ich bezweifle, dass Ihr Beispiel gültig ist. Haben Sie ein echtes Beispiel für eine Shell, bei der die var1=$varErweiterung einen Fehler verursacht?
Alex
@alex: Danke. Ich dachte, ich hätte das auf der Kommandozeile getestet, aber ich habe es falsch gemacht. Ich habe das Beispiel geändert.
Shawn J. Goff
Bei dem aktualisierten Beispiel ist es besser zu bedenken, dass Sie im Allgemeinen die zitierte Version wünschen sollten, da das Beispiel eher ein Eckfall ist.
Alex
9
@Shawn: Die Anführungszeichen sind in einer Zuordnung nicht erforderlich. Sie sind für die meisten anderen Zwecke erforderlich, einschließlich export VAR=$VAR1. Die geschweiften Klammern sind optional (siehe den vierten Absatz des Abschnitts, den Sie zitiert haben; dies ist bei allen Schalen vor POSIX und POSIX der Fall).
Gilles
60

${VAR}und $VARsind genau gleichwertig. Für eine einfache Variablenerweiterung ist der einzige Grund zu verwenden, ${VAR}wenn beim Parsen ansonsten zu viele Zeichen in den Variablennamen ${VAR1}_$VAR2eingehen würden , wie in (was ohne geschweifte Klammern äquivalent wäre ${VAR1_}$VAR2). Die meisten geschmückt Erweiterungen ( ${VAR:=default}, ${VAR#prefix}, ...) erfordern Klammern.

In einer Variablenzuweisung, Feldaufspaltung (dh Spaltung bei Leerraum im Wert) und Pfadnamenerweiterung (dh Globbing) ausgeschaltet sind, so VAR=$VAR1genau entspricht VAR="$VAR1", in allen POSIX Muscheln und in alle pre-POSIX sh , die ich habe gehört , von . (POSIX ref: einfache Befehle ). Legt aus demselben Grund VAR=*zuverlässig VARdie Literalzeichenfolge fest *. Natürlich VAR=a bsetzt VARauf , ada das bist ein separates Wort an erster Stelle. Im Allgemeinen sind doppelte Anführungszeichen nicht erforderlich, wenn die Shell-Syntax ein einzelnes Wort erwartet, zum Beispiel incase … in (aber nicht im Muster), aber auch dort müssen Sie vorsichtig sein: POSIX gibt dies zum Beispiel anUmleitungsziele ( >$filename) erfordern keine Anführungszeichen in Skripten, aber einige Shells, einschließlich Bash, erfordern die doppelten Anführungszeichen sogar in Skripten. Siehe Wann sind doppelte Anführungszeichen erforderlich? für eine gründlichere Analyse.

Sie benötigen die doppelten Anführungszeichen in anderen Fällen, insbesondere in export VAR="${VAR1}"(was äquivalent geschrieben werden kann export "VAR=${VAR1}") in vielen Shells (POSIX lässt diesen Fall offen). Aufgrund der Ähnlichkeit dieses Falls mit einfachen Zuweisungen und der Streuung der Liste der Fälle, in denen Sie keine doppelten Anführungszeichen benötigen, empfehle ich, nur doppelte Anführungszeichen zu verwenden, es sei denn, Sie möchten splitten und globieren.

Gilles
quelle
2
Im Allgemeinen zitiere ich Variablenerweiterungen immer, auch wenn ich weiß, dass der Wert keine IFSZeichen enthält, weil ich es mir zur Gewohnheit machen möchte. Die einzige Ausnahme ist, dass ich den Wert bei einer Variablenzuweisung nicht zitiere (sofern nicht erforderlich, z. B. wenn der Wert ein Leerzeichen enthält). Dies macht die Hervorhebung der Editor-Syntax nützlicher, wenn Befehlssubstitutionen wie z FOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}"). Anstatt alles in der "String" -Farbe zu färben, erhalte ich eine Syntaxhervorhebung des verschachtelten Codes. Deshalb vermeide ich auch Backticks.
Richard Hansen
Während >$filein POSIX - Skripte in Ordnung ist, ist es in der Bash nicht einmal , wenn nicht-interaktive (es sei denn , POSIX Einhaltung erzwungen wird $POSIXLY_CORRECToder --posix...).
Stéphane Chazelas
Es stimmt zwar, dass Zitate in nicht benötigt werden VAR=$VAR1, aber ich war manchmal überrascht local VAR=$VAR1, weil ich mich erinnere, dass ich in mancher Hinsicht anders gearbeitet habe, zumindest in einigen Shells. Aber atm, ich kann die Divergenz nicht reproduzieren.
dubiousjim
Ok, ich habe das Problem gefunden, an das ich mich erinnerte . Es zeigt sich nur in einigen Muscheln.
dubiousjim
@dubiousjim local VAR=$VAR1ist wie export VAR=$VAR1, es kommt auf die Shell an.
Gilles
8

Zitat

Bedenken Sie, dass für die variable Erweiterung das doppelte Anführungszeichen und für die starke Anführungszeichen, dh ohne Erweiterung, das einfache Anführungszeichen verwendet wird.

Erweiterung:

this='foo'
that='bar'
these="$this"
those='$that'

Ausgabe:

for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that

Es kann sinnvoll sein, zu erwähnen, dass Sie aus verschiedenen Gründen, wo immer möglich, Zitate verwenden sollten, von denen die besten sind, dass sie als Best Practice gelten, und aus Gründen der Lesbarkeit. Auch, weil Bash zuweilen skurril ist und häufig für unlogisch oder unvernünftig / unerwartet erscheinende Wege und das Ändern von impliziten Erwartungen zu explizit, was diese Fehlerfläche (oder das Potenzial dafür) reduziert.

Und obwohl es völlig legal ist, nicht zu zitieren, und in den meisten Fällen funktioniert, wird diese Funktionalität aus Bequemlichkeitsgründen bereitgestellt und ist wahrscheinlich weniger portabel. Die vollständig formale Praxis, die die Absicht und Erwartung widerspiegelt, ist das Zitieren.

Auswechslung

Bedenken Sie nun auch, dass das Konstrukt "${somevar}"für Substitutionsoperationen verwendet wird. Mehrere Anwendungsfälle, z. B. Ersatz und Arrays.

Ersatz (Abisolieren):

thisfile='foobar.txt.bak'
foo="${thisfile%.*}"   # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}"  # removes longest matching

for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar

Ersatz (Ersatz):

foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}"   #single occurrence
bar="${foobar//least/most}"  #global occurrence (all)

for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful

Arrays:

mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls  
alpha=($(ls temp/*))

echo "$alpha"         #  temp/foo.txt
echo "${alpha}"       #  temp/foo.txt
echo "${alpha[@]}"    #  temp/bar.txt  temp/foobar.txt  temp/foo.txt
echo "${#alpha}"      #  12 # length of first element (implicit index [0])
echo "${#alpha[@]}"   #  3  # number of elements
echo "${alpha[1]}"    #  temp/foobar.txt # second element
echo "${#alpha[1])"   #  15 # length of second element

for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt

All dies kratzt kaum an der Oberfläche des "${var}"Substitutionskonstrukts. Die endgültige Referenz für Bash-Shell-Skripte ist die libre-Online-Referenz TLDP The Linux Documentation Projecthttps://www.tldp.org/LDP/abs/html/parameter-substitution.html

SYANIDE
quelle
1
sehr informativ.
Orion Elenzil
0
ls -la

lrwxrwxrwx.  1 root root      31 Nov 17 13:13 prodhostname
lrwxrwxrwx.  1 root root      33 Nov 17 13:13 testhostname
lrwxrwxrwx.  1 root root      32 Nov 17 13:13 justname

ende dann:

env=$1
    if [ ! -f /dirname/${env}hostname ]

Erwähnenswert als klareres Beispiel für die Verwendung von Locken

Ninjabber
quelle