1

bash evaluates the following expression without any objections:

declare -A SPANISH=( [rojo]=red [verde]=green [azul]=blue )

...but it does not like this one one bit:

declare -A SPANISH=( $( echo "[rojo]=red [verde]=green [azul]=blue" ) )
bash: SPANISH: $( echo "[rojo]=red [verde]=green [azul]=blue" ): must use subscript when assigning associative array

I have tried many variations, but the result is always one or more instances of the must use subscript when assigning associative array error shown above.

This example is silly, of course. Its only purpose is to illustrate the problem of initializing a bash associative array using a command substitution.

Can this be done?

To be concrete, and to continue with the silly example above, what would be a command <COMMAND> such that

declare -A SPANISH=( $( <COMMAND> ) )

...produces the same final result as that produced by

declare -A SPANISH=( [rojo]=red [verde]=green [azul]=blue )

above?

Incidentally, zsh handles this situation without any problem:

$ declare -A SPANISH=( $( echo "rojo red verde green azul blue" ) )
$ echo "${SPANISH[azul]}"
blue
2

1 Answer 1

2
declare -A "SPANISH=($(echo '[rojo]=red [verde]=green [azul]=blue'))"

Or:

declare -A "SPANISH=$(echo '([rojo]=red [verde]=green [azul]=blue)')"

Or:

declare -A "$(echo 'SPANISH=([rojo]=red [verde]=green [azul]=blue)')"

For that matters,

Work for me with bash 5.1, though you might as well use eval as that's essentially what's happening here, bash ends up interpreting the output of the command as code.

For instance, with

cmd() { echo '[x$(reboot)]=y'; }
declare -A "a=($(cmd))"

Would run reboot just the same as:

eval "
  declare -A a=($(cmd))
"

Using eval explicitly would make it clearer that there's a path for a command injection vulnerability, and is more likely to be future-proof in case that messed up design is fixed in the future.

For a safer approach, you can get your cmd to output keys and values NUL-delimited (as bash variables can't contain NULs anyway) and fill up your associative array in a loop, with the additional usual caveat that associative arrays in bash can't have elements with an empty key.

fill_assoc() {
  local -n _assoc="$1"
  local _key _value
  while
    IFS= read -rd '' _key &&
    IFS= read -rd '' _value
  do
     _assoc[$_key]=$_value
  done
}
typeset -A assoc
fill_assoc assoc < <(printf '%s\0' rojo red verde green azul blue)
2
  • @terdon, take note of where the quotes are in there. The key being to quote the ( and ). Commented May 11, 2023 at 17:56
  • Ah, yes indeed. I (stupidly) assumed you were just using the OP's command. Thanks!
    – terdon
    Commented May 11, 2023 at 18:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .