Estoy escribiendo un conjunto de funciones de shell que quiero que funcionen tanto en Bash como en KornShell93, pero con Bash me encuentro con una advertencia de "referencia de nombre circular".
Esta es la esencia del problema:
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"
Ejecutándolo:
$ ksh script.sh
hello:boff
$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:
KornShell93 hace exactamente lo que quiero, pero Bash falla y también advierte sobre lo mismo en la línea 2 si something
variable en el script se llama var
en su lugar.
Me gustaría tener la var
la variable sea local para cada función, por eso uso typeset
, pero a Bash no parece gustarle "desreferenciar" una referencia de nombre a una variable con el mismo nombre que la referencia de nombre. No puedo usar local -n
o declare -n
ya que se rompería en ksh
que carece de estos, e incluso si los tuviera, no resuelve el problema.
La única solución que he encontrado es usar nombres de variables únicos en cada función , lo que parece bastante tonto ya que son locales.
El manual de Bash dice lo siguiente sobre typeset
:
typeset
[…]
-n
Asigne a cada nombre el nameref
atributo, convirtiéndolo en una referencia de nombre
a otra variable. Esa otra variable está
definida por el valor de name
. Todas las referencias y
asignaciones a name
, excepto por cambiar el -n
atributo en sí mismo, se realizan en la variable a la que hace referencia el valor del nombre.
[…]
Cuando se usa en una función, declare
y typeset
hacer que cada nombre
sea local, como con el local
comando, a menos que -g
la opción es
suministrada. Si el nombre de una variable va seguido de =value
, el valor
de la variable se establece en value
.
Es obvio que hay algo que no entiendo sobre las referencias de nombres de Bash y las variables locales de funciones.
Entonces, la pregunta es:en este caso, ¿me estoy perdiendo algo sobre el manejo de Bash de las variables de referencia de nombre, o se trata de un error/función incorrecta en Bash?
Actualizar :actualmente estoy trabajando con GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15)
así como con GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0)
. El Bash enviado con macOS es demasiado antiguo para conocer las referencias de nombres.
Actualizar :Aún más corto:
function bug {
typeset -n var="$1"
printf "%sn" "$var"
}
var="hello"
bug var
Resultados en bash: warning: var: circular name reference
. El var
en la función debería tener un alcance diferente de la var
en el ámbito mundial. Esto impone una restricción innecesaria a la persona que llama. La restricción es "no se le permite nombrar sus variables como quiera, porque puede haber un conflicto de nombres con una referencia de nombre (local) en esta función".
Respuesta aceptada:
Chet Ramey (mantenedor de Bash) dice
Hubo una extensa discusión sobre las referencias de nombre en bug-bash a principios de este
año. Tengo una sugerencia razonable sobre cómo cambiar este comportamiento,
y la revisaré después de que se publique bash-4.4.
Mientras tanto, estoy recurriendo a ofuscar un poco los nombres de mis variables nameref locales, para que no entren en conflicto dentro de la biblioteca ni (con suerte) con los nombres de variables de shell global.
En bash
5.0, esto se remedió ligeramente (pero no se solucionó realmente). El siguiente es el comportamiento observado:
$ 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
Esto muestra que funciona, pero que también hay algunas advertencias.
La entrada de NOTICIAS relevante dice
i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.