Bash Array – Indirect Return of All Elements in an Array

arraybash

The Bash man page describes use of ${!a} to return the contents of the variable whose name is the contents of a (a level of indirection).

I'd like to know how to return all elements in an array using this, i.e.,

a=(one two three)
echo ${a[*]}

returns

one two three

I would like for:

b=a
echo ${!b[*]}

to return the same. Unfortunately, it doesn't, but returns 0 instead.

Update

Given the replies, I now realise that my example was too simple, since of course, something like:

b=("${a[@]}")

Will achieve exactly what I said I needed.

So, here's what I was trying to do:

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST=LIST_$whichone
LIST=${!_LIST[*]}

Of course, carefully reading the Bash man page shows that this won't work as expected because the last line simply returns the indices of the "array" $_LIST (not an array at all).

In any case, the following should do the job (as pointed out):

LIST=($(eval echo \${$_LIST[*]}))

or … (the route that I went, eventually):

LIST_lys="lys1 lys2"
...
LIST=(${!_LIST})

Assuming, of course, that elements don't contain whitespace.

Best Answer

I think the use of indirect reference of bash variable should be treated literally.

Eg. For your original example:

a=(one two three)
echo ${a[*]} # one two three
b=a
echo ${!b[*]} # this would not work, because this notation 
              # gives the indices of the variable b which
              # is a string in this case and could be thought
              # as a array that conatins only one element, so
              # we get 0 which means the first element
c='a[*]'
echo ${!c} # this will do exactly what you want in the first
           # place

For the last real scenario, I believe the code below would do the work.

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST="LIST_$whichone"[*]
LIST=( "${!_LIST}" ) # Of course for indexed array only 
                     # and not a sparse one

It is better to use notation "${var[@]}" which avoid messing up with the $IFS and parameter expansion. Here is the final code.

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST="LIST_$whichone"[@]
LIST=( "${!_LIST}" ) # Of course for indexed array only 
                     # and not a sparse one
                     # It is essential to have ${!_LIST} quoted
Related Question