J'écris un ensemble de fonctions shell que je souhaite faire fonctionner à la fois dans Bash et KornShell93, mais avec Bash, je rencontre un avertissement "référence de nom circulaire".
C'est l'essence du problème :
function set_it {
typeset -n var="$1"
var="hello:$var"
}
function call_it {
typeset -n var="$1"
set_it var
}
something="boff"
call_it something
echo "$something"
Exécution :
$ ksh script.sh
hello:boff
$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:
KornShell93 fait exactement ce que je veux, mais Bash échoue et avertit également de la même chose à la ligne 2 si le something
la variable dans le script est nommée var
à la place.
J'aimerais avoir la var
la variable soit locale à chaque fonction, c'est pourquoi j'utilise typeset
, mais Bash ne semble pas aimer "déréférencer" un nameref à une variable portant le même nom que le nameref lui-même. Je ne peux pas utiliser local -n
ou declare -n
car il briserait ksh
qui en manque, et même si c'était le cas, cela ne résout pas le problème.
La seule solution que j'ai trouvée est d'utiliser des noms de variables uniques dans chaque fonction , ce qui semble plutôt idiot puisqu'ils sont locaux.
Le manuel Bash dit ce qui suit à propos de typeset
:
typeset
[…]
-n
Donnez à chaque nom lenameref
attribut, ce qui en fait une référence de nom
à une autre variable. Cette autre variable est
définie par la valeur dename
. Toutes les références et
affectations àname
, sauf pour changer le-n
attribut lui-même, sont effectuées sur la variable référencée par la valeur du nom.[…]
Lorsqu'il est utilisé dans une fonction,
declare
ettypeset
rendre chaque nom
local, comme avec lelocal
commande, sauf si la commande-g
option est
fournie. Si un nom de variable est suivi de=value
, la
valeur de la variable est définie survalue
.
Il est évident qu'il y a quelque chose que je ne comprends pas à propos des références de nom et des variables locales de fonction de Bash.
Donc, la question est :dans ce cas, ai-je raté quelque chose concernant la gestion par Bash des variables de référence de nom, ou s'agit-il d'un bogue/d'une mauvaise fonctionnalité dans Bash ?
Mettre à jour :Je travaille actuellement avec GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15)
ainsi qu'avec GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0)
. Le Bash fourni avec macOS est trop ancien pour connaître les références de noms.
Mettre à jour :Encore plus court :
function bug {
typeset -n var="$1"
printf "%sn" "$var"
}
var="hello"
bug var
Résultats dans bash: warning: var: circular name reference
. La var
dans la fonction devrait avoir une portée différente de la var
dans le périmètre global. Cela impose une restriction inutile à l'appelant. La restriction étant "vous n'êtes pas autorisé à nommer vos variables comme vous le souhaitez, car il peut y avoir un conflit de nom avec un nameref (local) dans cette fonction".
Réponse acceptée :
Chet Ramey (responsable de Bash) dit
Il y a eu une discussion approfondie sur les namerefs sur bug-bash plus tôt cette
année. J'ai une suggestion raisonnable sur la façon de modifier ce comportement,
et je l'examinerai après la sortie de bash-4.4.
En attendant, j'ai recours à un peu d'obscurcissement des noms de mes variables nameref locales, afin qu'elles n'entrent pas en conflit dans la bibliothèque ni (espérons-le) avec les noms de variables shell globales.
Dans bash
5.0, cela est légèrement corrigé (mais pas vraiment corrigé). Voici le comportement observé :
$ foo () { typeset -n var="$1"; echo "$var"; }
$ var=hello
$ foo var
bash: typeset: warning: var: circular name reference
bash: warning: var: circular name reference
bash: warning: var: circular name reference
hello
Cela montre que cela fonctionne, mais qu'il y a aussi quelques avertissements.
L'entrée NEWS correspondante indique
i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.