Werden für die Zuweisung lokaler Variablen Anführungszeichen benötigt?

36

Kann ich Anführungszeichen auf der rechten Seite einer lokalen Zuordnung sicher weglassen?

function foo {
    local myvar=${bar}
    stuff()
}

Ich interessiere mich hauptsächlich für bash, aber jede Information über Eckfälle in anderen Schalen ist willkommen.

rahmu
quelle
Ich denke, es macht keinen Unterschied, ob es in einer Zeile steht, wie Sie es in Ihrer Funktion haben. Aufträge müssen nicht zitiert werden. Siehe mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

Antworten:

41

Zitate sind erforderlich in export foo="$var"oder local foo="$var"(oder readonly, typeset, declareund anderen Variablen deklarieren Befehle ) in:

  • dash
  • das shvon NetBSD (auch basierend auf der Almquist-Shell).
  • Die shvon FreeBSD 9.2 oder älter (siehe die Änderung in 9.3 )
  • yash
  • zshmit Versionen vor 5.1 in kshoder shEmulation (oder für export var="$(cmd)"wo zshsonst Wortteilung durchführen würde (nicht Globbing)).

Da ansonsten die Variablenerweiterung einer Wortteilung und / oder Dateinamenerzeugung unterworfen wäre, wie bei jedem Argument für einen anderen Befehl.

Und werden nicht benötigt in:

  • bash
  • ksh (alle Implementierungen)
  • die shvon FreeBSD 9.3 oder neuer
  • Busybox auf Aschebasis sh(seit 2005)
  • zsh

In zshwird split + glob nie bei der Parametererweiterung ausgeführt, es sei denn, in shoder kshEmulation, aber split (nicht glob) wird bei der Befehlssubstitution ausgeführt. Seit Version 5.1 sind export/ localund andere Deklarationsbefehle wie in den anderen oben genannten Shells Dual Keyword / Builtin- Befehle, was bedeutet, dass keine Anführungszeichen erforderlich sind, auch nicht in sh/ kshemuliert und auch nicht für die Befehlssubstitution.

Es gibt spezielle Fälle, in denen ein Zitieren auch in diesen Shells erforderlich ist, obwohl:

a="b=some value"
export "$a"

Oder allgemeiner, links , wenn etwas von der =(einschließlich der =) notiert wird oder das Ergebnis einer Expansion (wie export 'foo'="$var", export foo\="$var"oder export foo$((n+=1))="$var"(das $((...))auch tatsächlich zitiert werden sollte) ...). Oder mit anderen Worten, wenn das Argument to exportkeine gültige Variablenzuweisung wäre, wenn es ohne das Argument geschrieben würde export.

Wenn die export/ localBefehlsnamen selbst zitiert wird (auch auszugsweise wie "export" a="$b", 'ex'port a="$b", \export a="$b"oder sogar ""export a="$b"), um die Anführungszeichen $bsind erforderlich , außer in AT & T kshund mksh.

Wenn export/ localoder ein Teil davon das Ergebnis einer Erweiterung (wie in cmd=export; "$cmd" a="$b"oder sogar export$(:) a="$b") oder in Dingen wie dryrun=; $dryrun export a="$b") ist, werden die Anführungszeichen in jeder Shell benötigt.

Im Fall von > /dev/null export a="$b"werden die Anführungszeichen in pdkshund einige seiner Ableitungen benötigt.

Denn command export a="$b"die Anführungszeichen werden in jeder Shell benötigt, aber mkshund ksh93(mit den gleichen Vorbehalten commandund exportnicht das Ergebnis einer gewissen Erweiterung).

Sie werden in keiner Shell benötigt, wenn sie geschrieben werden:

foo=$var export foo

(Diese Syntax ist auch mit der Bourne-Shell kompatibel zsh, funktioniert jedoch in neueren Versionen von nur in sh/ kshemulation).

(Beachten Sie, dass dies var=value local varnicht verwendet werden sollte, da das Verhalten von Shell zu Shell unterschiedlich ist.)

Beachten Sie auch, dass die Verwendung exportmit einer Zuweisung auch bedeutet, dass der Exit-Status von cmdin export var="$(cmd)"verloren geht. Es so zu machen, export var; var=$(cmd)hat dieses Problem nicht.

Beachten Sie diesen Sonderfall auch bei bash:

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
ab
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b

Mein Rat wäre, immer zu zitieren.

Stéphane Chazelas
quelle
3
Beachten Sie, dass in zshAnführungszeichen sind für erforderlich , local foo="$(cmd)"weil wordsplitting (aber nicht Dateinamen Generation) wird für nicht notierte Befehlsersetzungen durchgeführt (jedoch nicht für nicht notierte Parameter Erweiterungen), es sei denn , KSH_TYPESETaktiviert ist , wobei in diesem Fall Anführungszeichen sind nicht erforderlich. Sinn ergeben? Nein? Zitieren Sie dann immer alles, es sei denn, Sie wissen genau, was Sie tun.
Matt
2
@Matt, ich liebe dein Fazit. : D Es ist lustig, die meisten von dem, was ich von Shell - Skripten kamen aus diesem Stack gelernt habe, so dass ich nicht erkennen , dass immer Ihre Variablen zitieren ist nicht unter den Drehbuchautoren allgemein bekannt. Ich stelle fest, dass ich eine Menge Probleme mit vorhandenen Produktionsskripten habe, die von Leuten geschrieben wurden, die nicht zitierten und nicht genau wussten, was sie taten ....
Wildcard
3

Ich zitiere im Allgemeinen jede Verwendung von Variablen, bei denen Zeichen wie Leerzeichen vorkommen können. Andernfalls treten folgende Probleme auf:

#!/bin/bash

bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"
}

foo

Die Verwendung der Variablen in einer Zuweisung scheint keine Anführungszeichen zu erfordern, aber wenn Sie sie verwenden, wie im Beispiel, printfmüssen Sie sie dort angeben:

  printf "%s\n" "$myvar"

HINWEIS: Denken Sie daran, dass die Variable $IFSdie Trennzeichen bestimmt.

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.

Beispiel

Wenn das Debuggen in Bash aktiviert ist, können wir sehen, was hinter den Kulissen passiert.

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
hi
bye
+ printf '%s\n' 'hi bye'
hi bye

Oben sehen wir, dass die Variable $bargut an übergeben wurde, $myvaraber als wir sie verwendeten $myvar, mussten wir den Inhalt der Variablen kennen, $myvarals wir sie verwendeten.

slm
quelle
2
Die Wortteilung ist nicht das einzige Problem bei Variablen ohne Anführungszeichen. Sie müssen auch die Generierung von Dateinamen (auch bekannt als Globbing) berücksichtigen (obwohl dies (beides) bei Variablenzuweisungen und für bashund kshin local/ typeset... speziellen Builtins nicht zutrifft ).
Stéphane Chazelas