On Mon, Dec 08, 2025 at 11:57:02 -0500, Chet Ramey wrote:
> When you parse the compound assignment to an associative array assignment,
> the shell has to determine whether or not you're using subscripted array
> assignment or key-value pair assignment (kvpair). The first word in the
> list determines how the assignment treats the list. This happens before
> the individual words are expanded, since it determines how you expand
> keys, subscripts, and values.
>
> In this case, the word is
>
> $(
> echo [A]=a
> echo '[B]=b'
> echo ['C']=c
> )
>
> which is not a subscripted assignment, so it's treated as the key in a
> kvpair. There's no value, so the value is "".
This is unfortunate.
> If you single quote it, you'll just get a single element with the same key
> as above. If you double quote it, word expansion gives you
>
> declare -A a=(\n [A]=a\n[B]=b\n[C]=c\n)
>
> and `declare' runs that through compound array assignment. Since the first
> word is a subscripted assignment, that's how the assignment gets treated,
> and you end up with three elements.
But it's parsing the expanded content as shell syntax:
hobbit:~$ kv=(one 1 'two point five' 2.5 $'\n\t \n' punc)
hobbit:~$ declare -A aa="( "${kv[@]}" )"
hobbit:~$ declare -p aa
declare -A aa=([punc]="" [two]="point" [one]="1" [five]="2.5" )
This is even worse. There's a code injection vulnerability here:
hobbit:~$ kv=( x '$(date)' y 1 )
hobbit:~$ declare -A aa="( "${kv[@]}" )"
hobbit:~$ declare -p aa
declare -A aa=([y]="1" [x]="Mon Dec 8 14:31:58 EST 2025" )
As far as I know, the only safe way to serialize the keys and values of
an associative array into a string value, and then reassign that string
value back to its constituent associative array later, is to use the @K
expansion plus eval:
hobbit:~$ declare -A aa=( [one]=1 [two point five]=2.5 [$'\n\t \n']=punc )
hobbit:~$ saved="${aa[*]@K}"
hobbit:~$ printf '%s\n' "$saved"
$'\n\t \n' "punc" "two point five" "2.5" one "1"
hobbit:~$ eval declare -A "aa=($saved)"
hobbit:~$ declare -p aa
declare -A aa=([$'\n\t \n']="punc" ["two point five"]="2.5" [one]="1" )
If there's a better way, I'd love to know about it. Of course, one could
use a NUL delimiter between keys and elements in a file, but not in a
string value stored in a variable.