We are going to use eval
. For the least amount of risk, we prepare the value to be stored into the computed variable in a variable called val
The idiom is:
eval var_$i=\$val
The argument to eval
undergoes substitution, producing the syntax var_1=$val
. The dollar sign is escaped, and so the escape is removed and the dollar sign is preserved.
This var_1=$val
syntax is evaluated by eval
, resulting in the desired assignment.
Note that A=$B
assignments do not require quoting.
If a malicious user gains control over the $i
variable, they can fool our eval
into doing bad things. For instance, suppose i
contains this text:
foo=bar; rm -rf ~/*; bar
then eval
will be invoked with the argument:
var_foo=bar; rm -rf ~/*; bar=$val
a syntactically correct command sequence consisting of two assignments sandwiching a recursive removal. So you have to be very careful about how i
acquires its value.
Bash has indirect variables and namerefs (by imitation of similar features found in the Korn shell).
Quick demo: indirect vars:
$ var=TERM
$ echo ${!var}
screen-256color
namerefs:
$ declare -n var=TERM
$ echo $var
screen-256color
$ var=ansi
$ echo $var
ansi
$ echo $TERM
ansi
Using a nameref we can create an alias for var_$i
and set it that way:
$ i=42
$ declare -n ref=var_$i
$ ref=content
$ echo $var_42
content
This is safer than using eval
, and probably more performant; just not portable. The eval
method uses only POSIX shell features.
declare
builtin might help, I can't find the link now but try:declare i=1 var_$i='true'; echo "$var_1"
$i
is always numeric, you don't even need an an associative array, just a plain numeric-indexed one.i=1; var[i]='true'; echo "${var[1]}"
. In any case, dynamic variable names are a mess, and should be avoided if at all possible (usually by using some sort of array instead).