13

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?

  • Could you edit your post to say which shell you're using, or what portability requirements you have? – Michael Homer Jun 30 '18 at 1:19
  • @MichaelHomer Sure, but how exactly can I check this information? – Rafael Muynarsk Jun 30 '18 at 1:20
  • It's more something that you choose than something to check. For example, are you running your scripts with ash, or bash, or csh, or dash, ..., or zsh, or POSIX sh, or do you need to work across different systems? – Michael Homer Jun 30 '18 at 1:23
  • @MichaelHomer Ah, I see... I'm using bash. I'll just change the final question and insert a new tag then. – Rafael Muynarsk Jun 30 '18 at 1:26
21

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

10

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 a eval echo $test command;
  • eval evaluates echo $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).

  • Sure, that's a mistype. The original post has single quotes. Fixed. – Danila Kiver Jun 29 '18 at 22:55
  • 4
    I 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 using eval that you mentioned. – Gordon Davisson Jun 30 '18 at 2:13
8

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.

3

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.