Bash - Get the VALUE of 'nested' variable into another variable [Edit: Indirect Variable Expansion]

Viewed 2267

I'm trying to get get the VALUE of a 'nested' variable into another variable and/or use the value directly as shown below

Below is an example scenario which exactly explains where I'm stuck

$ USER1_DIR=./user1/stuff
$ USER2_DIR=./user2/stuff
$ USER3_DIR=./user3/stuff

#User will be taken as input, for now assuming user is USER1 
$ USER="USER1"
$ DIR=${USER}_DIR

$ echo $DIR
>> USER1_DIR

$ DIR=${${USER}_DIR}
>> -bash: ${${USER}_DIR}: bad substitution

Challenge 1:

Get DIR value to ./user1/stuff when the input is USER1

or

Get ./user1/stuff as output when the input is USER1

After I'm able to get through Challenge 1, I've to add some content to a file in the user directory like below


Desired output is as below


$ echo "Some stuff of user1" >> $DIR/${DOC}$NO

# Lets say DOC="DOC1" and NO="-346"
# So the content has to be added to ./user1/stuff/DOC1-346
# Assume that all Directories exists

FYI, The above code will be a part of a function in a bash script and it will be executed only on a Linux server.

Note : I don't know what to call variable DIR hence used the term 'nested' variable. It would be great to know what is it called, greatly appreciate any insight. :)

1 Answers

You can use eval, variable indirection ${!...}, or reference variables declare -n.

In the following, I will use lowercase variable names, since uppercase variable names are special by convention. Especially overwriting $USER is bad, because that variable normally contains your user name (without explicitly setting it). For the following code fragments assume the following variables:

user1_dir=./user1/stuff
user=user1

Eval

eval "echo \${${user}_dir}"
# prints `./user1/stuff`

Eval is a bash built-in that executes its arguments as if they were entered in bash itself. Here, eval is called with the argument echo "${user1_dir}".

Using eval is considered bad practice, see this question.

Variable Indirection

When storing the name of variable var1 inside another variable var2, you can use the indirection ${!var2} to get the value of var1.

userdir="${user}_dir"
echo "${!userdir}"
# prints `./user1/stuff`

Reference Variables

Instead of using indirection every time, you also can declare a reference variable in bash:

declare -n myref="${user}_dir"

The reference can be used similar to variable indirection, but without having to write the !.

echo "$myref"
# prints `./user1/stuff`

Alternatives

Your script may become easier when using (associative) arrays. Arrays are variables that store multiple values. Single values can be accessed by using an index. Normal arrays use natural numbers as indices. Associative arrays use arbitrary strings as indices.

(Normal) Arrays

# Create an array with three entries
myarray=(./user1/stuff ./user2/stuff ./user3/stuff)

# Get the first entry
echo "${myarray[0]}"

# Get the *n*-th entry
n=2
echo "${myarray[$n]}"

Associative Arrays

Declare an associative array with three entries

# Create an associative array with three entries
declare -A myarray
myarray[user1]=./user1/stuff
myarray[user2]=./user2/stuff
myarray[user3]=./user3/stuff

# Get a fixed entry
echo "${myarray[user1]}"

# Get a variable entry
user=user1
echo "${myarray[$user]}"
Related