6

Trying to write some nested loop, and I'm not getting how to write it. Perhaps I'm looking in a wrong direction but what I'm trying to write is:

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

So then I would like to iterate the subgroups (in the future more bars and foos will come), and inside them iterate them as they can have a different number of elements.

The desired output would be something like:

group name: bar with group members: alpha bravo charlie
 working on alpha of the bar group
 working on bravo of the bar group
 working on charlie of the bar group
group name: foo with group members: delta echo foxtrot golf
 working on delta of the foo group
 working on echo of the foo group
 working on foxtrot of the foo group
 working on golf of the foo group

The closes code I've wrote seems fail in the bar and foo arrays and its expansion with the elements on each set.

for group in "${subgroups[@]}"; 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

And the output is:

group name: bar with group members: 0
 working on 0 of the bar group
group name: foo with group members: 0
 working on 0 of the foo group
Chris Davies
128k16 gold badges176 silver badges323 bronze badges
asked Oct 7, 2019 at 10:51
2

2 Answers 2

9

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

answered Oct 7, 2019 at 10:57
1
  • Might be worth clarifying that the ! with an array is supposed to be key syntax, and doesnt work as a name-ref the way regular variables do Commented Oct 7, 2019 at 12:40
4

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
answered Oct 11, 2019 at 18:15

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.