Seems that the recommended way of doing indirect variable setting in bash is to use eval
:
var=x; val=foo
eval $var=$val
echo $x # --> foo
The problem is the usual one with eval
:
var=x; val=1$'\n'pwd
eval $var=$val # bad output here
(and since it is recommended in many places, I wonder just how many scripts are vulnerable because of this...)
In any case, the obvious solution of using (escaped) quotes doesn't really work:
var=x; val=1\"$'\n'pwd\"
eval $var=\"$val\" # fail with the above
The thing is that bash has indirect variable reference baked in (with ${!foo}
), but I don't see any such way to do indirect assignment -- is there any sane way to do this?
For the record, I did find a solution, but this is not something that I'd consider "sane"...:
eval "$var='"${val//\'/\'\"\'\"\'}"'"
The main point is that the recommended way to do this is:
eval "$var=\$val"
with the RHS done indirectly too. Since eval
is used in the same
environment, it will have $val
bound, so deferring it works, and since
now it's just a variable. Since the $val
variable has a known name,
there are no issues with quoting, and it could have even been written as:
eval $var=\$val
But since it's better to always add quotes, the former is better, or even this:
eval "$var=\"\$val\""
A better alternative in bash that was mentioned for the whole thing that
avoids eval
completely (and is not as subtle as declare
etc):
printf -v "$var" "%s" "$val"
Though this is not a direct answer what I originally asked...