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
NarūnasK
  • 2,276
  • 4
  • 25
  • 35

1 Answers1

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

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
  • 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 04 '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 04 '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 05 '18 at 07:42