bkvaluemeal
bkvaluemeal

Reputation: 448

Dynamic bash associative array keys

I've been wrestling with this problem for a long time and can't seem to find a working solution.

Suppose I have declared two associative arrays.

declare -A FOO_ARRAY=(
  [a]="first"
  [b]="second"
  [c]="third"
)

declare -A BAR_ARRAY=(
  [a]="first"
  [b]="second"
  [c]="third"
)

I can get a list of keys like so:

$ echo ${!FOO_ARRAY[@]}
c b a
$ echo ${!BAR_ARRAY[@]}
c b a

I can also dynamically deference a key from the array by doing something like this:

for KEY in FOO BAR
do
  temp="${KEY}_ARRAY[a]"
  echo ${!temp}
done

However, if you notice that the operator for dynamically referencing variables is also the same to get the list of keys from an associative array, how could I make something like this possible in order to dynamically list the keys in an associative array?

A naive example like this results in an invalid variable name error.

$ export NAME=foo
$ export temp="\!${NAME^^}_ARRAY[@]"
$ echo ${!temp}
bash: \!FOO_ARRAY[@]: invalid variable name

What I'm searching for is a way to dynamically return the list of keys from an associative array as if the above code sample returned:

c b a

Upvotes: 1

Views: 1769

Answers (3)

wjandrea
wjandrea

Reputation: 32997

Use declare -n. From help declare:

-n  make NAME a reference to the variable named by its value

Example:

declare -A foo_array=(
  [a]="first"
  [b]="second"
  [c]="third"
)
declare -n temp="foo_array"
echo "${!temp[@]}"  # -> a b c

For more details, see info bash under the "Bash Builtins" section.

Upvotes: 3

that other guy
that other guy

Reputation: 123490

You can use a nameref:

declare -rgA FOO_ARRAY=(
  [a]="first"
  [b]="second"
  [c]="third"
)

name="foo"
declare -n array="${name^^}_ARRAY"
echo "The keys are: " "${!array[@]}"

Upvotes: 3

Avinash Yadav
Avinash Yadav

Reputation: 916

This Will Work

NAME=foo
temp="${NAME^^}_ARRAY[@]"
echo ${!temp}

Explanation: here temp will store " FOO_ARRAY[@] " as string only and when echo it in reference way it does print the value.

Example

declare -rgA FOO_ARRAY=(
  [a]="first"
  [b]="second"
  [c]="third"
)

declare -rgA BAR_ARRAY=(
  [a]="first"
  [b]="second"
  [c]="third"
)

echo ${!FOO_ARRAY[@]}
echo ${!BAR_ARRAY[@]}

for KEY in FOO BAR
do
  temp="${KEY}_ARRAY[a]"
  echo ${!temp}
done

NAME=foo
temp="${NAME^^}_ARRAY[@]"
echo ${!temp}

Run:

a b c
a b c
first
first
first second third

Upvotes: 0

Related Questions