Bash and Zsh – Equivalent of Bash Indirect Referencing ${!FOO} in Zsh

bashforvariable substitutionzsh

${!FOO} performs a double substitution in bash, meaning it takes the (string) value of FOO and uses it as a variable name.
zsh doesn’t support this feature.

Is there a way to make this work the same in bash and zsh?

Background:

I’ve got a list of environment variables, like

PATH MAIL EDITOR

and want to first print the variable names and afterwards their values.

This works in bash but not zsh:

for VAR in LIST
do
        echo $VAR
        echo ${!VAR}
done

It should be somehow possible “the old way” with eval, but I can’t get it to work:

for VAR in LIST
do
        echo $VAR
        echo `eval \$$VAR`
done

I’m never going to understand why I can’t simply do arbitrary deep substitutions like ${${VAR}} or even ${${${VAR}}} if need be, so an explanation for that would be nice, too.

Best Answer

Both bash and zsh have a way to perform indirect expansion, but they use different syntax.

It's easy enough to perform indirect expansion using eval; this works in all POSIX and most Bourne shells. Take care to quote properly in case the value contains characters that have a special meaning in the shell.

eval "value=\"\${$VAR}\""
echo "$VAR"
echo "$value"

${${VAR}} doesn't work because it's not a feature that any shell implements. The thing inside the braces must conform to syntax rules which do not include ${VAR}. (In zsh, this is supported syntax, but does something different: nested substitutions perform successive transformations on the same value; ${${VAR}} is equivalent to $VAR since this performs the identity transformation twice on the value.)