2

I am trying to do an indirect reference to values in an array in bash.

anotherArray=("foo" "faa")

foo=("bar" "baz")
faa=("test1" "test2")


for indirect in ${anotherArray[@]}
do

echo ${!indirect[0]}
echo ${!indirect[1]}

done

This does not work. I tried a lot of differenct things to get the different values of $foo by echoing $indirect but I can only get the first value, all values, '0' or nothing at all.

valh
  • 21
  • 3

3 Answers3

3

You have to write the index in the variable used for indirection :

anotherArray=("foo" "faa")
foo=("bar" "baz")
faa=("test1" "test2")

for indirect in ${anotherArray[@]}; do
  all_elems_indirection="${indirect}[@]"
  second_elem_indirection="${indirect}[1]"
  echo ${!all_elems_indirection}
  echo ${!second_elem_indirection}
done

If you want to iterate over every element of every arrays referenced in anotherArray, do the following :

anotherArray=("foo" "faa")
foo=("bar" "baz")
faa=("test1" "test2")

for arrayName in ${anotherArray[@]}; do
  all_elems_indirection="${arrayName}[@]"
  for element in ${!all_elems_indirection}; do
    echo $element;
  done
done

Alternatively you could directly store the whole indirections in your first array : anotherArray=("foo[@]" "faa[@]")

Aaron
  • 24,009
  • 2
  • 33
  • 57
  • Okay, I thought there might be a more elegant way to do this instead of assigning every single value of the array to a separate variable to use it in the loop. Thanks! – valh Oct 28 '16 at 15:05
3

Modern versions of bash adopt a ksh feature, "namevars", that's a perfect fit for this issue:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*|4.[012]) echo "ERROR: Bash 4.3+ needed" >&2; exit 1;; esac

anotherArray=("foo" "faa")

foo=("bar" "baz")
faa=("test1" "test2")

for indirectName in "${anotherArray[@]}"; do
  declare -n indirect="$indirectName"
  echo "${indirect[0]}"
  echo "${indirect[1]}"
done
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
1

You need do it in two steps

$ for i in ${anotherArray[@]}; do 
     t1=$i[0]; t2=$i[1]; 
     echo ${!t1} ${!t2};  
  done

bar baz
test1 test2
karakfa
  • 66,216
  • 7
  • 41
  • 56
  • It's not exactly two steps, he could set `anotherArray=("foo[@]" "faa[1]")` and the indirections would access the specific elements rather than just the first. – Aaron Oct 28 '16 at 15:02
  • Yes, there can be infinitely many more variations but that's not what the OP is asking for. – karakfa Oct 28 '16 at 15:10