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 
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

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 doCommentedOct 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 

    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.