I'm trying to have two layers of indirection, though let me know if I'm a victim of the XY problem

Boiled Down Explanation of What I'd Like to Achieve

> test1=\$test2
> test2="string to print"
> echo $test2
string to print
> echo $test1

This all makes sense, but what I want is to perform a command using $test1 and print out string to print. My gut reaction was that this should work

> echo $(echo $test1)

Bollocks. Does anyone else know if this is possible?

More Detailed Explanation of Why I Wish to Accomplish This

I want to create a text file template containing $variables which can be re-used to generate many text files. My thinking is: set environment variables, process the template file and output to another file.


> #set vars
> cat template.txt | magic_var_expansion_cmd > out1.txt
> #set vars
> cat template.txt | magic_var_expansion_cmd > out2.txt
> #set vars
> cat template.txt | magic_var_expansion_cmd > out3.txt

This could obviously be used in a script, and in more sophisticated ways but this is the MVP in my mind's eye.

$ test1="hello"
$ test2="test1"

$ echo "${!test2}"

From the bash manual:

If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. If parameter is a nameref, this expands to the name of the variable referenced by parameter instead of performing the complete indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[@]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.

For the second part of the question, I would probably try to avoid using actual shell variables in the template, and instead use easy to parse placeholders and replace these using a tool like sed.

There are a few similar questions around, including "How to replace placeholder strings in document with contents from a file", "Tool to create text files from a template" and "How to replace a list of placeholders in a text file?" (and there are others too).

  • This is really close to what I was looking for, with one wrinkle. If it were test2=test1 hello, then echo "${!test2}" doesn't print "hello hello", it prints nothing. Jan 30 '17 at 17:25
  • 2
    If the string contains variables, but isn't exculsively itself the name of a variable, is this possible? Jan 30 '17 at 17:27

use eval

$ test1=\$test2
$ test2="string to print"
$ echo $test2
string to print
$ eval echo $test1
string to print
  • 1
    This is also useful for "deliteralizing" strings with special characters like tildes or curly braces so they can be passed around in a variable for later expansion. Mar 6 '20 at 21:11

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