0

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 a b") and output a b in the subshell.

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

  • Bear in mind that `*` or `@` is being resolved by the interpreter that is calling `bash -c`, not by the bash process you're running. If you wanted array expansion within the child process, you might use single quotes, but you'd also have to contend with the fact that arrays cannot be passed as part of the environment to a child process. – ghoti Nov 25 '19 at 17:01

2 Answers2

2

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.

choroba
  • 231,213
  • 25
  • 204
  • 289
1

"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
oguz ismail
  • 1
  • 16
  • 47
  • 69