2

I found a similar question here, but it does not seem to be identical, and none of the answers provide the output that I want. I have an array, for which I want to find how many elements it contains by accessing it using dynamically generated name.

declare -a array0=(2 4 2 5)  # contains 4 values
indx=0
Name="array$indx"            # create a name reference => array0

# I know how to obtain an indexed value by INDIRECT reference:
val0=${!Name[0]}
# I also know how to get array length using DIRECT name
len=${#array0[@]}

What I need is find the number of elements of the array0 by referencing it using variable Name

len=${#!Name[@]}             # the syntax is incorrect

Any suggestions for implementation?

EDIT:
I was wrong about being able to access the array entries using this:

val0=${!Name[0]}

It only works for indx=0, so if I wanted to get other entries from the array, it simply returns an empty string:

val4=${!Name[4]}          #does not work

or

i=4
val4=${!Name[$i]}         # does not work
2

You can use eval explicitly, but don't overuse it:

eval "len=\${#$Name[@]}"
  • Thank you - this works. Let's see if there are other ways to do it – Nazar May 31 '17 at 20:39
  • No sure about the consequences of overusing "eval", but it seems to be working very well for finding the number of elements in the referenced array, as well as reading the specific element from array using eval elem=\${$Name[$i]} – Nazar Jun 1 '17 at 20:08
4

With bash-4.3 or above, you can use namerefs:

a0=(a b c)
i=0
typeset -n Name="a$i"
echo "${#Name[@]}"

or you can always use eval. In any case, don't be fooled into thinking using bash namerefs is safer than eval. Like for eval, you still need to make sure the content of $Name is a valid shell variable name. Values like x[`evil-command>&2`0] would still cause that evil-command to be executed when you expand $Name or ${#Name}. Same applies to ${!var}.

With ksh93, you could use multi-dimensional arrays instead:

a[0]=(a b c)
i=0
echo "${#a[i][@]}"

zsh has more consistent ways to combine its expansion operators:

a0=(a b c)
i=0
name=a$i
echo ${(P)#name}

(P for indirect parameter expansion).

  • Almost there. Could you, please, see my edit? – Nazar Jun 1 '17 at 19:40
  • I cannot do "typeset", because I need variable Name to contain the string of the original array, i.e. "array0" – Nazar Jun 1 '17 at 19:52
  • @Naz, then you can use Name=a$i; typeset -n ref="$Name"; echo "${#ref[@]}" or use eval or the other alternatives. – Stéphane Chazelas Jun 1 '17 at 19:57

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.