5

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

Hemanth
  • 159
  • 1
  • 12
  • 1
    What you want is called *indirect* variable expansion (for lookup) or assignment (for modification). See [BashFAQ #6](http://mywiki.wooledge.org/BashFAQ/006). And BTW, all-caps names are used by variables with meaning to the OS or system -- use lowercase names for your own variables to avoid overwriting them by mistake. See relevant POSIX spec @ http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html; fourth paragraph speaks to naming conventions (when reading it, keep in mind that setting a regular shell variable will overwrite any like-named environment variable). – Charles Duffy Sep 23 '17 at 20:17
  • @Charles, Thanks for the insights. I'll keep them in mind. – Hemanth Sep 24 '17 at 02:09

1 Answers1

9

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]}"
Socowi
  • 25,550
  • 3
  • 32
  • 54
  • 1
    Quite a lot of effort to build an extensive and correct answer to an obvious duplicate. I don't know whether to be critical of the decision to answer or impressed at the quality of that answer. :) – Charles Duffy Sep 23 '17 at 21:11
  • @Socowi, Thanks for the answer. No words. This is one of the best answer I've seen here. Thanks again.. :) – Hemanth Sep 24 '17 at 02:06
  • Could you expand on Variable Indirection? The link doesn't work. – konyak Aug 25 '20 at 20:10
  • @konyak Seems like the linked answer was deleted. I added my own explanations for indirection. I hope this is what you needed. – Socowi Aug 25 '20 at 21:04
  • Yup that's perfect, thanks! – konyak Aug 26 '20 at 23:25