2

Consider the following example, it seems it's working fine with the index 0:

$ a1=(1 2 3)
$ a2=(a b c)
$ for x in a1 a2; do echo "${!x}"; done
1
a
$ for x in a1 a2; do echo "${!x[0]}"; done
1
a

However with the index 1 it prints nothing:

$ for x in a1 a2; do echo "${!x[1]}"; done    

Arrays just by themselves are fine:

$ echo "${a1[1]} ${a2[1]}"
2 b

Edit - A real life use case based on ilkkachu answer

SHIBB=(https://shibboleth.net/downloads/service-provider/3.0.2/ shibboleth-sp-3.0.2 .tar.gz)
XERCES=(http://apache.mirrors.nublue.co.uk//xerces/c/3/sources/ xerces-c-3.2.1 .tar.gz)
XMLSEC=(http://apache.mirror.anlx.net/santuario/c-library/ xml-security-c-2.0.1 .tar.gz)
XMLTOOL=(http://shibboleth.net/downloads/c++-opensaml/latest/ xmltooling-3.0.2 .tar.gz)
OPENSAML=(http://shibboleth.net/downloads/c++-opensaml/latest/ opensaml-3.0.0 .tar.gz)

typeset -n x
for x in XERCES XMLSEC XMLTOOL OPENSAML SHIBB; do
  url="${x[0]}" app="${x[1]}" ext="${x[2]}"
  [ -f "./${app}${ext}" ] || wget "${url}${app}${ext}"
  tar -xf "./${app}${ext}"
  cd "./${app}" && ./configure && make -j2 && make install && ldconfig
  cd ..
done
6

"${!x[1]}" is an indirect reference using the element at index 1 of the array x.

$ foo=123; bar=456; x=(foo bar); echo "${!x[1]}"
456

In current versions of Bash (4.3 and above), you can use namerefs to get what you want:

$ a=(00 11 22 33 44)
$ typeset -n y=a
$ echo "${y[3]}"
33

that is, with the nameref set up, "${y[3]}" is a reference to element 3 in the array named by y.


To loop over the arrays as you do in your question, you'd simply make x a nameref.

a1=(1 2 3); a2=(a b c)
typeset -n x;
for x in a1 a2; do
    echo "${x[1]}"
done

The assignments done by the for loop change the value of x itself (changing what the reference points to). A regular assignment (x=123, or x[1]=123) changes the variable currently referenced by x. So this would change both a1[1] and a2[1] to foo:

typeset -n x;
for x in a1 a2; do
    x[1]=foo
done

The reason "${!x[0]}" seems to work is that x and x[0] are equivalent. If you had echo "${x[0]}" inside your loop (without the bang), you'd get a1, a2, the same as with echo "$x".

  • Could you please give an example how to use typeset -n in the for loop, just like I showed in the question? – NarūnasK Sep 4 '18 at 21:22
  • @NarūnasK, edited. Though I do wonder what your actual use case is. Looping over array names like that seems a bit quaint. – ilkkachu Sep 4 '18 at 22:15
  • I have a bunch of the tarballs, which I have to download, unpack, cd into the directory, configure/make... Basically very repetitive steps, which now (thanks to you) fit in the for loop very nicely :) Please see edited question. – NarūnasK Sep 5 '18 at 7:42
0

Indirection works by expanding one value and then using the result of the expansion as the new name of a variable:

$ a=abc; x=a; echo "${!x}"
abc

$ a=(one two three four); x=a[0]; y=a[1]; z=a[3]; echo "${!x}   ${!y}   ${!z}"
one   two   four

So, for your example:

$ a1=(1 2 3);   a2=(a b c)
$ for x in a1[0] a2[0] a1[1] a1[2]; do echo "${!x}"; done
1
a
2
b

For your "real life use case", you could do:

SHIBB=(https://shibboleth.net/downloads/service-provider/3.0.2/ shibboleth-sp-3.0.2 .tar.gz)
XERCES=(http://apache.mirrors.nublue.co.uk//xerces/c/3/sources/ xerces-c-3.2.1 .tar.gz)
XMLSEC=(http://apache.mirror.anlx.net/santuario/c-library/ xml-security-c-2.0.1 .tar.gz)
XMLTOOL=(http://shibboleth.net/downloads/c++-opensaml/latest/ xmltooling-3.0.2 .tar.gz)
OPENSAML=(http://shibboleth.net/downloads/c++-opensaml/latest/ opensaml-3.0.0 .tar.gz)

for s in XERCES XMLSEC XMLTOOL OPENSAML SHIBB; do
    x=${s}[0] y=${s}[1] z=${s}[2]
    url="${!x}" app="${!y}" ext="${!z}"
    [ -f "./${app}${ext}" ] || wget "${url}${app}${ext}"
    tar -xf "./${app}${ext}"
    cd "./${app}" && ./configure && make -j2 && make install && ldconfig
    cd ..
done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.