Des guillemets sont-ils nécessaires pour l'affectation de variables locales?

36

Puis-je omettre en toute sécurité des guillemets à droite d'une affectation locale?

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

Je suis principalement intéressé par bash, mais toute information sur les cas de coin dans d'autres coquilles sont les bienvenues.

Rahmu
la source
Je pense que cela ne fait aucune différence si c'est sur une ligne comme vous l'avez dans votre fonction. Les affectations n'ont pas besoin d'être citées. Voir mpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

Réponses:

41

Les cotes sont nécessaires export foo="$var"ou local foo="$var"(ou readonly, typeset, declareet d' autres variables déclarant commandes ) en:

  • dash
  • le shde NetBSD (également basé sur le shell Almquist).
  • La version shde FreeBSD 9.2 ou plus ancienne (voir la modification dans la 9.3 )
  • yash
  • zshavec les versions antérieures à 5.1 in kshou shemulation (ou pour export var="$(cmd)"zsheffectuerait le fractionnement des mots autrement (non globbing)).

Comme dans le cas contraire, le développement des variables serait sujet à la division des mots et / ou à la génération du nom de fichier, comme dans tout argument d'une autre commande.

Et ne sont pas nécessaires dans:

  • bash
  • ksh (toutes les implémentations)
  • la version shde FreeBSD 9.3 ou plus récente
  • busybox 'basé sur les cendres sh(depuis 2005)
  • zsh

Dans zsh, split + glob n'est jamais utilisé lors du développement des paramètres, à moins que in shou kshémulation, mais split (et non glob), lors de la substitution de commande. Depuis la version 5.1, les commandes export/ localet autres déclarations sont devenues des commandes doubles à mots clés / intégrées, comme dans les autres shells ci-dessus, ce qui signifie que les guillemets ne sont pas nécessaires, même dans sh/ kshémulation et même pour la substitution de commandes.

Il y a des cas spéciaux où la citation est nécessaire même dans ces coquilles bien que:

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

Ou plus généralement, si tout ce qui reste du =(y compris le =) est cité ou le résultat d'une expansion (comme export 'foo'="$var", export foo\="$var"ou export foo$((n+=1))="$var"(qui $((...))devrait également être cité en fait) ...). Ou en d'autres termes, lorsque l'argument exportne serait pas une affectation de variable valide s'il était écrit sans le export.

Si le export/ localnom de la commande elle - même est cité (même en partie comme "export" a="$b", 'ex'port a="$b", \export a="$b", ou même ""export a="$b"), les guillemets autour $bsont nécessaires , sauf pour AT & T kshet mksh.

Si export/ localou une partie de celle-ci est le résultat d'une expansion (comme dans cmd=export; "$cmd" a="$b"ou même export$(:) a="$b") ou dans des choses comme dryrun=; $dryrun export a="$b"), alors les guillemets sont nécessaires dans chaque shell.

Dans le cas de > /dev/null export a="$b", les guillemets sont nécessaires dans pdkshet certains de ses dérivés.

Car command export a="$b", les guillemets sont nécessaires dans chaque shell mais mkshet ksh93(avec les mêmes mises en garde concernant commandet exportne résultant pas d'une certaine expansion).

Ils ne sont nécessaires dans aucun shell lorsqu'ils sont écrits:

foo=$var export foo

(Cette syntaxe étant également compatible avec le shell Bourne mais dans les versions récentes de zsh, ne fonctionne que dans sh/ kshémulation).

(notez que cela var=value local varne devrait pas être utilisé car le comportement varie selon les coquilles).

Notez également que l'utilisation exportd'une affectation signifie également que le statut de sortie de cmdin export var="$(cmd)"est perdu. Le faire en tant que export var; var=$(cmd)n'a pas ce problème.

Méfiez-vous également de ce cas particulier avec bash:

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

Mon conseil serait de toujours citer.

Stéphane Chazelas
la source
3
Notez que les zshguillemets sont nécessaires local foo="$(cmd)"car le fractionnement des mots (mais pas la génération du nom de fichier) est effectué pour les substitutions de commandes non entre guillemets (mais pas pour les extensions de paramètres non entre KSH_TYPESETguillemets ), sauf si elle est activée, auquel cas les guillemets ne sont pas nécessaires. Avoir un sens? Non? Ensuite, citez toujours tout, sauf si vous savez exactement ce que vous faites.
Matt
2
@ Matt, j'aime votre conclusion. : D Il est drôle, la plupart de ce que je l' ai appris de scripts shell est venu de ce StackExchange, de sorte que je ne savais pas que toujours citer vos variables est pas connaissance commune parmi les scénaristes. Je trouve que j'ai beaucoup de mal à faire des scripts de production existants écrits par des gens qui ne citent pas , et qui ne savaient pas exactement ce qu'ils faisaient ....
Wildcard
3

Je cite généralement toute utilisation de variables où il pourrait y avoir des caractères tels que des espaces blancs. Sinon, vous rencontrerez des problèmes comme celui-ci:

#!/bin/bash

bar="hi bye"

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

foo

L'utilisation de la variable dans une affectation ne semble pas nécessiter les guillemets, mais lorsque vous allez l'utiliser comme dans le printfvous aurez besoin de le citer ici:

  printf "%s\n" "$myvar"

Remarque: rappelez-vous que la variable $IFSest ce qui gouverne ce que sont les caractères de séparation.

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>''.

Exemple

Lorsque le débogage est activé dans Bash, nous pouvons voir ce qui se passe dans les coulisses.

$ 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

Dans ce qui précède, nous pouvons voir que la variable, a bien $barété transmise, $myvarmais lorsque nous sommes allés utiliser, $myvarnous devions être au courant du contenu de cette variable $myvar.

slm
la source
2
fractionnement mot n'est pas le seul problème avec les variables non cotées, vous devez considérer la génération de nom de fichier (aka englobement) et (bien que ( les deux) ne s'applique pas dans les affectations de variables et bashet kshdans local/ typeset... builtins spéciaux).
Stéphane Chazelas