3

Because bash doesn't support "arrays in arrays", I'm trying to dynamize variable name when calling arrays.

bash version : 4.2

I used this expansion method: https://stackoverflow.com/a/18124325/9336478

#!/bin/bash
# data are pre-defined and type is determined later

declare -a data_male
declare -a data_female

data_male=(value1 value2)
data_female=(value3 value4)

type="male" 

for value in ${${!data_$type}[@]};do
  echo $value
done

and it did not work

line 20: ${${!data_$type}[@]} : bad substitution

How do I sort this out?

5
  • 1
    see: stackoverflow.com/a/44831174/10971581 Commented Jul 19, 2021 at 7:36
  • Which version of Bash are you using? Commented Jul 19, 2021 at 8:40
  • @vdavid I'm currently using 4.2 edited the post Commented Jul 19, 2021 at 8:57
  • 1
    You can't nest expansions in a single step like that, you need to set a variable to what you want expanded (and that'd include things like [@] to get all elements of an array). Something like data_type_contents="data_${type}[@]"; for value in ${!data_type_contents}; do ... Commented Jul 19, 2021 at 9:37
  • do you have the option of installing a newer version of bash? Commented Jul 19, 2021 at 13:08

2 Answers 2

3

If OP can get a newer version of bash installed then a nameref (name reference, available in bash 4.3+) could be used:

declare -a data_male
declare -a data_female

data_male=(value1 value2)
data_female=(value3 value4)

type="male"

declare -n arr="data_${type}"       # dynamically declare arr[] as a name ref to data_male[]

for ndx in "${!arr[@]}"
do
    echo "${arr[${ndx}]}"
done

This generates:

value1
value2
Sign up to request clarification or add additional context in comments.

Comments

2

Unfortunately, in Bash 4.2 you need to eval the array.

printf -v evaluator 'for value in ${%s[@]};do\n  echo $value\ndone' "data_$type"
eval "$evaluator"

printf will inject the name of the array designated by data_$type into the %s part, and then the result of the string is assigned to the variable evaluator.

So, the first part builds a string designed to be evaluated, and then you evaluate it.

Instead of newline characters \n you can also use actual newlines:

printf -v evaluator 'for value in ${%s[@]};do
  echo $value
done' "data_$type"
eval "$evaluator"

You should make sure that the contents of your arrays are safe because this can be used to inject malicious code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.