Reputation: 9100
In my bash script I have two arrays. Depending on some logic either one or another shall be used, so I'm getting the name of a required array in a variable varName
. I can surely get the values of this array with the code below but is there a way to get it's keys? Tried several options but no luck.
declare -A foo=([a]=b [c]=d)
declare -A bar=([e]=f [g]=h)
varName=foo
varArray=$varName[@]
echo ${!varArray}
Thanks.
Upvotes: 3
Views: 488
Reputation: 183
There is an IFS-safe method to get the keys (or values) of an array indirectly:
declare -a things=("an apple" "a banana")
declare -a tmp
arrayName=things
eval "tmp=(\"\${$arrayName[@]}\")"
# "${tmp[@]}" is now ("an apple" "a banana")
Upvotes: 0
Reputation: 531275
Not without resorting to eval
, unfortunately. To be safe, make sure varName
is just a single valid identifier.
[[ varName =~ ^[a-zA-Z_][a-zA-Z_0-9]+$ ]] && eval "echo \${!$varName[@]}"
eval
is necessary to provide a second round of parsing and evaluation. In the first round, the shell performs the usual parameter expansion, resulting in the string echo ${!foo[@]}
being passed as the single argument to eval
. (In particular, the first dollar sign was escaped and so is passed literally; $varName
is expanded to foo
; and the quotes are removed as part of quote removal. eval
then parses that string and evaluates it.
$ eval "echo \${!$varName[@]}"
# echo ${!foo [@]}
# The above is the argument that `eval` sees, after the shell
# does the normal evaluation before calling `eval`. Parameter
# expansion replaces $varName with foo and quote removal gets
# rid of the backslash before `$` and the double quotes.
a c
If you are using bash
4.3 or later, you can use a nameref.
declare -n varName=foo
for key in "${!varName[@]}"; do
echo "$key"
done
Upvotes: 3