Is it possible to print the content of the content of a variable with shell script? (indirect referencing)
Solution 1
You can accomplish this using bash's indirect variable expansion (as long as it's okay for you to leave out the $
from your reference variable):
$ var=test
$ test="my string"
$ echo "$var"
test
$ echo "${!var}"
my string
3.5.3 Shell Parameter Expansion
Solution 2
For the case when the variable name contained in var
is prefixed with $
you may use eval
:
$ var='$test'
$ test="my string"
$ eval echo $var
my string
What happens here:
- bash expands
$var
to the value$test
, producing aeval echo $test
command; -
eval
evaluatesecho $test
expression and produces a desired result.
Note, that using eval
in general may be dangerous (depending on what is stored in var
), so prefer avoiding it. Indirect expansion feature is better for your case (but you need to get rid of $
sign in $test
).
Solution 3
Similar to Jesse_b's answer, but using a name reference variable instead of variable indirection (requires bash
4.3+):
$ declare -n var=test
$ test="my string"
$ echo "$var"
my string
The name reference variable var
holds the name of the variable it's referencing. When the variable is dereferenced as $var
, that other variable's value is returned.
bash
resolves name references recursively:
$ declare -n var1=var2
$ declare -n var2=test
$ test="hello world"
$ echo "$var1"
hello world
For completeness, using an associative array (in bash
4.0+) is also one way of solving this, depending on requirements:
$ declare -A strings
$ strings[test]="my string"
$ var=test
$ echo "${strings[$var]}"
my string
This provides a more flexible way of accessing more than one value by a key or name that may be determined dynamically. This may be preferable if you want to collect all values of a particular category in a single array, but still be able to access them by some key (e.g. names accessible by ID, or pathnames accessible by purpose etc.) as it does not pollute the variable namespace of the script.
Solution 4
With zsh
:
$ var='$test'
$ test='*'
$ printf '%s\n' ${(e)var}
*
With any Bourne-like shell
$ eval 'printf "%s\n" "'"$var"'"'
*
Remember that in those shells variable expansions must be quoted to prevent split+glob (zsh
being an exception) and echo
can't be used for arbitrary data.
Since with both (e)
and eval
there is shell code evaluation, it's important the content of $var
stay within your control as otherwise that can be an arbitrary command injection vulnerability (same with ${!var}
approaches).
Related videos on Youtube
Rafael Muynarsk
Updated on September 18, 2022Comments
-
Rafael Muynarsk over 1 year
Let's suppose I've declared the following variables:
$ var='$test' $ test="my string"
If I print their contents I see the following:
$ echo $var $test $ echo $test my string
I'd like to find a way to print the content of the content of
$var
(which is the content of$test
). So I tried to do the following:$ echo $(echo $var) $test
But here the result is
$test
and not"my string"
... Is it possible to print the content of the content of variables using bash?-
Admin almost 6 yearsCould you edit your post to say which shell you're using, or what portability requirements you have?
-
Admin almost 6 years@MichaelHomer Sure, but how exactly can I check this information?
-
Admin almost 6 yearsIt's more something that you choose than something to check. For example, are you running your scripts with
ash
, orbash
, orcsh
, ordash
, ..., orzsh
, or POSIXsh
, or do you need to work across different systems? -
Admin almost 6 years@MichaelHomer Ah, I see... I'm using bash. I'll just change the final question and insert a new tag then.
-
-
javaamtho almost 6 yearsI always recommend double-quoting variable references (to avoid trouble from unexpected word splitting and wildcard expansion). With
eval
, you need two layers of double-quotes, line this:eval echo "\"$var\""
. Mind you, this doesn't do anything about the other dangers of usingeval
that you mentioned.