Count number of elements in bash array, where the name of the array is dynamic (i.e. stored in a variable)
you should handle that stuff in the index evals. and you can indirect through your indirection variable's indices if you make it an array.
a=(abc1 def2 ghi3 jkl4 mno5)
r=('a[c=${#a[@]}]' a\[i] a\[@])
for i in 0 1 2 3 4 5
do c=
printf "<%s>\n" "${!r-${!r[i<c?1:2]}}"
printf "\n\tindex is $i and count is $c\n\n"
done
<abc1>
index is 0 and count is 5
<def2>
index is 1 and count is 5
<ghi3>
index is 2 and count is 5
<jkl4>
index is 3 and count is 5
<mno5>
index is 4 and count is 5
<abc1>
<def2>
<ghi3>
<jkl4>
<mno5>
index is 5 and count is 5
Because bash
's indices are 0-based, the total count of array objects will always work out to one more than than the highest set index, and so:
c=
echo "${a[c=${#a[@]}]-this index is unset}" "$c"
this index is unset 5
...the parameter expands out to the default word if any is provided.
If one is not provided:
c=
${!r}
echo "$c"
5
...there's no harm done.
In the loop I track an $i
ndex variable and check if it is at least as large as $c
ount. When it is lesser I expand the $r
eference var to a[i]
because it is a valid index, but when it is equal or greater I expand the $r
ef to the entire $a
rray.
Here it is in a function:
ref_arr(){
local index=-1 count=
local ref=( "$1[ count= \${#$1[@]} ]"
"$1[ index ]" "$1[ @ ]"
) && printf "input array '%s' has '%d' members.\n" \
"$1" "${!ref-${count:?invalid array name: "'$1'"}}"
while [ "$((index+=1))" -lt "$count" ]
do printf "$1[$index] == '%s'\n" "${!ref[1]}"
done
}
some_array=(some "dumb
stuff" 12345\'67890 "" \
'$(kill my computer)')
ref_arr some_array
ref_arr '$(echo won'\''t work)'
input array 'some_array' has '5' members.
some_array[0] == 'some'
some_array[1] == 'dumb
stuff'
some_array[2] == '12345'67890'
some_array[3] == ''
some_array[4] == '$(kill my computer)'
bash: count: invalid array name: '$(echo won't work)'
Related videos on Youtube
drwatsoncode
Scientist by day, programmer by night. Sleep? I wish...
Updated on September 18, 2022Comments
-
drwatsoncode almost 2 years
Brief statement of the question:
Is there built-in bash method to count number of elements in bash array, where the name of the array is dynamic (i.e. stored in a variable), without resorting to making a fully copy of the array or using
eval
?More information:
Using bash parameter substitution, one can do the following:
- Determine the length of an array:
myArr=(A B C); echo ${#myArr[@]}
. - Indirectly reference a variable by name:
NAME=myVar; echo ${!NAME}
(this also applies to array elements):
NAME=myArr[1]; echo ${!NAME}
But if the name of an array is stored in another variable, how can one determine the number of elements in the array? (One might consider this a combination of the above two parameter substitutions.) For example:
myArr=(A B C D) NAME=myArr # Get the number of elements in the array indirectly referenced by NAME. count=${#$NAME[@]} # This syntax is invalid. What is the right way?
Below are multiple attempts that all FAIL:
# Setup for following attempts: myArr=(A B C D) NAME=myArr EXPR1=$NAME[@] # i.e. EXPR1='myArr[@]' EXPR2=#$NAME[@] # i.e. EXPR2='#myArr[@]' # Failed attempts to get the lengh of the array indirectly: 1. count=${#$NAME[@]} # ERROR: bash: ...: bad substitution 2. count=${#!EXPR1} # ERROR: bash: !EXPR}: event not found 3. count=${#\!EXPR1} # ERROR: bash: ...: bad substitution 4. count=${!#EXPR1} # ERROR: bash: ...: bad substitution 5. count=${!EXPR2} # Returns NULL
I've also tried some other variants of the above, but have not yet found anything that works without either: (A) making a copy of the array or (B) by using
eval
.Working Methods:
There are a couple ways of solving this that are probably not optimal (but correct me if I'm wrong):
Method 1: Copy the Array
Assign the array to another (statically-named) variable and get the number of elements in it.
EXPR=$NAME[@] arrCopy=( "${!EXPR}" ) count=${#arrCopy}
Method 2: Use
eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}' eval $EXPR # Now count is set to the length of the array
Summary:
Is there any built-in method (i.e. parameter substitution syntax) in bash to determine the length of an array indirectly? If not, what is the most efficient way to do this? I assume it is the
eval
method above, but are there security or performance issues witheval
? - Determine the length of an array:
-
drwatsoncode over 8 yearsThanks for replying, but your answer is what I already described under the section "Method 1: Copy the Array". The question also specifically stated that the array length should be determined "without resorting to making a fully copy of the array", which is exactly what you did.
-
drwatsoncode over 8 yearsLet us continue this discussion in chat.