Indirect variable assignment in bash

Eli Barzilay picture Eli Barzilay · Mar 30, 2012 · Viewed 33k times · Source

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//\'/\'\"\'\"\'}"'"

Answer

David Foerster picture David Foerster · Jun 7, 2013

Bash has an extension to printf that saves its result into a variable:

printf -v "${VARNAME}" '%s' "${VALUE}"

This prevents all possible escaping issues.

If you use an invalid identifier for $VARNAME, the command will fail and return status code 2:

$ printf -v ';;;' '%s' foobar; echo $?
bash: printf: `;;;': not a valid identifier
2