2022-07-21
I recently came across a useful feature in bash that I hadn’t seen before. The feature is called “indirect expansion”. It’s documented in the bash man pages1, although not prominently.
Indirect expansion allows a parameter to be expanded twice. First, the
parameter is expanded in the regular way. Then, the result of the first
expansion is expanded. This allows you to store the name of a parameter within
another parameter, and perform the full expansion in a single step. It works by
adding a !
prefix to the parameter to be expanded.
For example:
foo=42
bar=foo
echo ${bar} # regular parameter expansion, prints foo
echo ${!bar} # indirect expansion, prints 42
What is this actually useful for? When I needed it, I was writing a bash script where user input caused different bash variables to be evaluated. The general outline of the script looked like this:
# Initialise some variables that hold filenames. Note
# that the variable names follow a particular structure.
foo_x_filename="..."
foo_y_filename="..."
bar_x_filename="..."
bar_y_filename="..."
baz_x_filename="..."
baz_y_filename="..."
# Read input from the user, which will
# be used to select one of the variables:
read -p "resource > " resource # user inputs foo, bar, or baz
read -p "xy > " xy # user inputs x or y
# ... validation of $resource and $xy omitted for clarity ...
# Construct a variable name programatically based on the input from the user:
var_name="${resource}_${xy}_filename"
# Use **indirect expansion** to expand var_name
# to the filename in a single step.
filename="${!var_name}"
# Do something with the filename.
$EDITOR "$filename"
The actual script was much more complicated, but the excerpt above gives the general idea. Indirect expansion is a useful tool in these sorts of scenarios, because the mapping from the user input to the variable to expand becomes short and concise.
An alternative to indirect expansion would be to use an associative array,
mapping strings such as 'bar_x_path'
to their corresponding paths.
Search for the section titled “Parameter Expansion” in man 1 bash
.
Indirect expansion is described in the paragraph starting with “If the first
character of parameter is an exclamation point (!)"… ↩︎