简体   繁体   中英

Bash: quoted array expansion leads to strange results

While experimenting with bash arrays, I stumbled upon behaviour I find hard to explain.

> arr=("a" "b")
> bash -c "echo ${arr[*]}"
a b
> bash -c "echo ${arr[@]}"
a

The relevant part of the bash manual states:

${!name[@]}, ${!name[*]} : If name is an array variable, expands to the list of array indices (keys) assigned in name. [...] When '@' is used and the expansion appears within double quotes, each key expands to a separate word.

As I understand it, I would expect the latter example to expand from bash -c "echo ${arr[@]}" to bash -c "echo \\"a\\" \\"b\\"" (or even bash -c "echo ab" ) and output ab in the subshell.

So, which is the correct behaviour? The observed behaviour? The behaviour I expect? Or something entirely different?

You can run the code under set -xv to see how bash expands the variables:

choroba@triangle:~ $ (set -xv ; arr=("a" "b") ; bash -c "echo ${arr[@]}")
+ arr=("a" "b")
+ bash -c 'echo a' b
a

"echo ${arr[@]}" is expanded to two words, echo a and b , the first one is used as a command to run, the second one is interpreted as the value for the $0 or name of the shell. Any following arguments would be used to set the positional parameters.

"echo ${arr[@]}" expands to two words, echo a , and b . And the manual also says

If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.

So, you're assigning b to $0 there.

Proof of concept:

$ arr=(a b)
$ bash -c "echo \$0; echo ${arr[@]}"
b
a

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM