Après avoir lu 24.2. Variables locales , j'ai pensé que déclarer une variable var
avec le mot clé local
signifiait que la valeur de var
n'était accessible que dans le bloc de code délimité par les accolades d'une fonction.
Cependant, après avoir exécuté l'exemple suivant, j'ai découvert que var
peut également être consulté, lu et écrit à partir des fonctions invoquées par ce bloc de code - c'est-à-dire même si var
est déclaré local
to outerFunc
, innerFunc
est toujours capable de le lire et de modifier sa valeur.
#!/usr/bin/env bash
function innerFunc() {
var='new value'
echo "innerFunc: [var:${var}]"
}
function outerFunc() {
local var='initial value'
echo "outerFunc: before innerFunc: [var:${var}]"
innerFunc
echo "outerFunc: after innerFunc: [var:${var}]"
}
echo "global: before outerFunc: [var:${var}]"
outerFunc
echo "global: after outerFunc: [var:${var}]"
Production:
global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc`
outerFunc: before innerFunc: [var:initial value]
innerFunc: [var:new value] # `innerFunc` has access to `var` ??
outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ??
global: after outerFunc: [var:]
Q: Est-ce un bug dans mon shell (bash 4.3.42, Ubuntu 16.04, 64bit) ou est-ce le comportement attendu?
EDIT: Résolu. Comme l'a noté @MarkPlotnick, c'est bien le comportement attendu.
Les variables shell ont un portée dynamique . Si une variable est déclarée comme locale pour une fonction, cette étendue reste jusqu'à ce que la fonction retourne.
Il existe deux exceptions:
dans ksh93, si une fonction est définie avec la syntaxe standard function_name () { … }
, alors ses variables locales obéissent à la portée dynamique. Mais si une fonction est définie avec la syntaxe ksh function function_name { … }
alors sa variable locale obéit à la portée lexicale/statique, donc elle n'est pas visible dans les autres fonctions appelées par cela.
le zsh/private
le plugin autoloadable dans zsh
fournit un mot clé/intégré private
qui peut être utilisé pour déclarer une variable à portée statique.
frêne, bash, pdksh et dérivés, bosh n'ont qu'une portée dynamique.
Ce n'est pas un bug, l'appel dans le contexte de externalFunc utilise cette copie locale de $ var. Le "local" dans externalFunc signifie que le global n'est pas modifié. Si vous appelez innerFunc en dehors de externalFunc, alors il y aura un changement au $ var global, mais pas au $ var local du externalFunc. Si vous avez ajouté "local" à innerFunc, alors $ var de externalFunc ne serait pas modifié - en substance, il y en aurait 3:
pour utiliser le format d'espace de noms de Perl, en quelque sorte.
Vous pouvez utiliser une fonction pour forcer la portée locale:
sh_local() {
eval "$(set)" command eval '\"\$@\"'
}
Exemple:
x() {
z='new value'
printf 'function x, z = [%s]\n' "$z"
}
y() {
z='initial value'
printf 'function y before x, z = [%s]\n' "$z"
sh_local x
printf 'function y after x, z = [%s]\n' "$z"
}
printf 'global before y, z = [%s]\n' "$z"
y
printf 'global after y, z = [%s]\n' "$z"
Résultat:
global before y, z = []
function y before x, z = [initial value]
function x, z = [new value]
function y after x, z = [initial value]
global after y, z = [initial value]
Dans function innerFunc()
le var='new value'
N'a pas été déclaré comme local, donc il est disponible dans la portée visible (une fois que la fonction a été appelée).
Inversement, dans function outerFunc()
le local var='initial value'
A été déclaré comme local, donc il n'est pas disponible dans la portée globale (même si la fonction a été appelée).
Étant donné que innerFunc()
a été appelée en tant qu'enfant de outerFunc()
, var se trouve dans la portée locale de outerFunc()
.
man 1 bash
Peut aider à clarifier
local [option] [nom [= valeur] ...]
Pour chaque argument, une variable locale nommée nom est créée et une valeur affectée. L'option peut être l'une des options acceptées par declare. Lorsque local est utilisé dans une fonction, le nom de la variable a une portée visible limitée à cette fonction et à ses enfants. ...
Le comportement implicite attendu dans la description peut être obtenu en déclarant local var='new value
Dans function innerFunc()
.
Comme d'autres l'ont dit, ce n'est pas un bogue dans le shell bash. Tout fonctionne comme il se doit.