bash array of arrays

This is a pretty common problem in bash, to reference array within arrays for which you need to create name-references with declare -n. The name following the -n will act as a nameref to the value assigned (after =). Now we treat this variable with nameref attribute to expand as if it were an array and do a full proper quoted array expansion as before.

for group in "${subgroups[@]}"; do
    declare -n lst="$group"
    echo "group name: ${group} with group members: ${lst[@]}"
    for element in "${lst[@]}"; do
        echo -en "\tworking on $element of the $group group\n"
    done
done

Note that bash supports nameref's from v4.3 onwards only. For older versions and other workarounds see Assigning indirect/reference variables


The minimum changes to make your script work correctly, it becomes:

#!/bin/bash

declare -a bar=("alpha" "bravo" "charlie")
declare -a foo=("delta" "echo" "foxtrot" "golf")

declare -a groups=("bar" "foo")

for group in "${groups[@]}"; do
    lst="$group[@]"
    echo "group name: ${group} with group members: ${!lst}"
    for element in "${!lst}"; do
        echo -en "\tworking on $element of the $group group\n"
    done
done

The two main changes are:

  • Don't use "${!lst[@]}", not even "${!group[@]}" to access array elements. This syntax is only to access array indexes.

    Do use ${!lst}".

  • The variable lst should be set to contain the string that you would have written inside a normal ${ }, that is: lst=foo[@] on first level and to lst="$group[@]" if you need that the name of the array is also indirect via the value of variable group.

     lst="$group[@]"
    

An equivalent syntax with namerefs has no ! (nor it needs) to expand values.
As a consequence it needs the [@] removed above.

echo "using namerefs"

for group in "${groups[@]}"; do
    declare -n lst=$group
    echo "group name: ${group} with group members: ${lst[@]}"
    for element in "${lst[@]}"; do
        echo -en "\tworking on $element of the $group group\n"
    done
done