Pytheas
Pytheas

Reputation: 43

How can I reference an existing bash array using a 2nd variable containing the name of the array?

My closest most helpful matches when I searched for an answer ahead of posting:

Iterate over array in shell whose name is stored in a variable

How to use an argument/parameter name as a variable in a bash script

How to iterate over an array using indirect reference?

My attempt with partial success:

#!/bin/bash

declare -a large_furry_mammals
declare -a array_reference  
# I tried both declaring array_reference as an array and 
# not declaring it as an array.  no change in behavior.

large_furry_mammals=(horse zebra gorilla)


size=large
category=mammals

tmp="${size}_furry_${category}"
eval array_reference='$'$tmp

echo tmp=$tmp
echo array_reference[0]=${array_reference[0]}
echo array_reference[1]=${array_reference[1]}

Output

tmp=large_furry_mammals
array_reference[0]=horse
array_reference[1]=

Expectation

I would have expected to get the output zebra when I echoed array_reference[1].

...but I'm missing some subtlety...

Why can I not access elements of the index array beyond index 0? This suggests that array_reference is not actually being treated as an array.

I'm not looking to make a copy of the array. I want to reference (what will be) a static array based on a variable pointing to that array, i.e., ${size}_furry_${category} -> large_furry_mammals.

I've been successful with the general idea here using the links I've posted but only as long as its not an array. When it's an array, it's falling down for me.

Addendum Dec 5, 2018

bash 4.3 is not available in this case. @benjamin's answer does work on under 4.3.

I'll be needing to loop over the resulting array variable's contents. This kinda dumb example I gave involving mammals was just to describe the concept. There's actually a real world case around this. I have set of static reference arrays and an input string would be parsed to select which array was relevant and then I will loop over the array that was selected. I could do a case statement but with more than 100 reference arrays that would be the direct but overly verbose way to do it.

This pseudo code is probably better example of what I'm going after.

m1_array=(x a r d)
m2_array=(q 3 fg d)
m3_array=(c e p)

Based on some logic...select which array prefix you need.
x=m1

for each element in ${x}_array
do
   some-task
done

I'm doing some testing with @eduardo's solution to see if I can adapt the way he references the variables to get to my endgame.

** Addendum #2 December 14, 2018 **

Solution

I found it! Working with @eduardo's example I came up with the following:

#!/bin/bash

declare -a large_furry_mammals
#declare -a array_reference

large_furry_mammals=(horse zebra gorilla)


size=large
category=mammals

tmp="${size}_furry_${category}[@]"

for element in "${!tmp}"
do
    echo $element
done

Here is what execution looks like. We successfully iterate over the elements of the array string that was built dynamically.

./example3b.sh

horse
zebra
gorilla

Thank you everyone.

Upvotes: 4

Views: 1263

Answers (2)

Eduardo
Eduardo

Reputation: 7841

declare -a large_furry_mammals
declare -a array_reference
large_furry_mammals=(horse zebra gorilla)

size=large
category=mammals

echo ${large_furry_mammals[@]}
tmp="${size}_furry_${category}"
array_reference=${tmp}"[1]"
eval ${array_reference}='bear'
echo tmp=$tmp
echo ${large_furry_mammals[@]}

Upvotes: 1

Benjamin W.
Benjamin W.

Reputation: 52112

If you have Bash 4.3 or newer, you can use namerefs:

large_furry_mammals=(horse zebra gorilla)
size=large
category=mammals
declare -n array_reference=${size}_furry_$category
printf '%s\n' "${array_reference[@]}"

with output

horse
zebra
gorilla

This is a reference, so changes are reflected in both large_furry_mammals and array_reference:

$ array_reference[0]='donkey'
$ large_furry_mammals[3]='llama'
$ printf '%s\n' "${array_reference[@]}"
donkey
zebra
gorilla
llama
$ printf '%s\n' "${large_furry_mammals[@]}"
donkey
zebra
gorilla
llama

Upvotes: 2

Related Questions