On 12/8/25 2:34 PM, Greg Wooledge wrote:
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:

Because you told it to.

hobbit:~$ kv=(one 1 'two point five' 2.5 $'\n\t \n' punc)

This is an indexed array.

declare -a kv=([0]="one" [1]="1" [2]="two point five" [3]="2.5" [4]=$'\n\t \n' [5]="punc")

hobbit:~$ declare -A aa="( "${kv[@]}" )"

You have one round of word expansion here, and you don't do anything
special to quote the white space. This command turns into the (unquoted)
equivalent of

declare -A $'aa=( one 1 two point five 2.5 \n\t \n punc )'

and the spaces, newlines, and tab are just whitespace. It's as if you wrote

declare -A aa=( one 1 two point five 2.5 punc )

hobbit:~$ declare -p aa
declare -A aa=([punc]="" [two]="point" [one]="1" [five]="2.5" )

which is what you get.

This is even worse.  There's a code injection vulnerability here:

You forced two rounds of word expansion.

hobbit:~$ kv=( x '$(date)' y 1 )

Another indexed array:

declare -a kv=([0]="x" [1]="\$(date)" [2]="y" [3]="1")

hobbit:~$ declare -A aa="( "${kv[@]}" )"

You get

declare -A aa=( x $(date) y 1 )

and the $(date) is the value for the kvpair, which is expanded as usual.
There is no difference between what you wrote above and

declare -A aa='( x $(date) y 1 )'
or
declare -A aa='( [x]=$(date) [y]=1 )'
or
declare -A aa=( x $(date) y 1 )
or
declare -A aa=( [x]=$(date) [y]=1 )

You removed the part of my message where I said double quoting the rhs of
the assignment statement -- which results in word expansion -- and giving
declare an unquoted compound assignment as its argument, is only supported
for backwards compatibility. I don't think you should use it.


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:

OK. If you need to do that, then use that method.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [email protected]    http://tiswww.cwru.edu/~chet/

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

Reply via email to