Asignación de variables indirectas en bash
Parece que la forma recomendada de realizar la configuración de variables indirectas en bash es usar eval
:
var=x; val=foo
eval $var=$val
echo $x # --> foo
El problema es el habitual con eval
:
var=x; val=1$'\n'pwd
eval $var=$val # bad output here
(y dado que se recomienda en muchos lugares, me pregunto cuántos scripts son vulnerables debido a esto...)
En cualquier caso, la solución obvia de usar comillas (de escape) realmente no funciona:
var=x; val=1\"$'\n'pwd\"
eval $var=\"$val\" # fail with the above
La cuestión es que bash tiene una referencia de variable indirecta integrada (con ${!foo}
), pero no veo ninguna forma de realizar una asignación indirecta. ¿Existe alguna forma sensata de hacer esto?
Para que conste, encontré una solución, pero esto no es algo que yo consideraría "sano"...:
eval "$var='"${val//\'/\'\"\'\"\'}"'"
Bash tiene una extensión printf
que guarda su resultado en una variable:
printf -v "${VARNAME}" '%s' "${VALUE}"
Esto evita todos los posibles problemas de escape.
Si utiliza un identificador no válido para $VARNAME
, el comando fallará y devolverá el código de estado 2:
$ printf -v ';;;' '%s' foobar; echo $?
bash: printf: `;;;': not a valid identifier
2
Una forma ligeramente mejor, evitando las posibles implicaciones de seguridad del uso eval
, es
declare "$var=$val"
Tenga en cuenta que declare
es sinónimo de typeset
en bash
. El typeset
comando es más ampliamente compatible ( ksh
y zsh
también úselo):
typeset "$var=$val"
En las versiones modernas de bash
, se debe utilizar un nameref.
declare -n var=x
x=$val
Es más seguro que eval
, pero aún no es perfecto.