flying_potato_chip
flying_potato_chip

Reputation: 51

Double curly braces in Bash - bad substitution

This works:

echo ${!var_pointing_to_another_var}

This doesn't:

echo ${!${var}_string_suffix}

In other words, I have a variable consisting of two parts: the first part is another variable, the second part is a string suffix. Together, they form a variable that would point to another variable. But I get a bad substitution error.

Due to readability and security issues, I want to avoid the eval command.

Upvotes: 5

Views: 1919

Answers (2)

Jasen
Jasen

Reputation: 12442

As far as I know, this is the only way:

t="${var}_string_suffix"
echo "${!t}"

Upvotes: 4

ormaaj
ormaaj

Reputation: 6627

http://mywiki.wooledge.org/BashFAQ/006

What you probably want is an associative array.

# The most common multi-dimensional array emulation for bash >= 4.0 is
# to use an associative array with delimiter.
typeset -A arr=([foo;bar]=test)
printf '%s\n' "${arr[$(printf '%q;%q' "$var1" "$var2")]}" # bash 4

Indirection using ${!var} is less portable and not necessarily safer than eval. eval based indirection is well-understood, while bash indirect expansion can introduce obscure bugs without a solid understanding of its mechanics and careful input validation. The above wiki page provides a good introduction. "namerefs" are another workaround for bash 4.3, but they generally shouldn't be used in this way.

var1=foo
var2=bar
foobar=test
ref=${var1}${var2}
printf '%s\n' "${!ref}" # print test (bash-only, <= 4.3)

# Note: not a great example of nameref usage
typeset -n ref2=${var1}${var2}
printf '%s\n' "$ref2" # bash >= 4.3 / ksh93 / mksh

# Correct eval usage
if [[ $ref == [a-zA-Z_]+([a-zA-Z0-9_]) ]]; then
    eval printf '%s\\n' "\${$ref}" # POSIX
    eval printf '%s\\n' "$(printf '${%q}' "$ref")" # bash / ksh93 / zsh
fi

Upvotes: 2

Related Questions