lanza
lanza

Reputation: 1642

bash: What EXACTLY does `"${array[@]}"` do?

Let's say I have a script echoargs

$ echo $#
$ echo $*

I can either put quotes around an array expansion and get this behavior:

$ arr=("a b" "c d" "e f")
$ echoargs "${arr[@]}"
3
a b c d e f

Or I can not put quotes and get this behavior:

$ echoargs ${arr[@]}
6
a b c d e f

And then this chunk of code:

$ for i in "q ${arr[@]} q"; do echo $i; done
q a b
c d
e f q

Upvotes: 0

Views: 64

Answers (3)

melpomene
melpomene

Reputation: 85887

https://www.gnu.org/software/bash/manual/bashref.html#Arrays:

Any element of an array may be referenced using ${name[subscript]}. The braces are required to avoid conflicts with the shell’s filename expansion operators. If the subscript is ‘@’ or ‘*’, the word expands to all members of the array name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS variable, and ${name[@]} expands each element of name to a separate word. When there are no array members, ${name[@]} expands to nothing. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. This is analogous to the expansion of the special parameters ‘@’ and ‘*’.

(Emphasis mine.)

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

Use a different incarnation of echoargs:

echoargs() { echo $#; printf '[%s]\n' "$@"; }
arr=("a" "b  c" "  d  e  f  " " multiple
    lines too")
echoargs ${arr[@]}
echoargs "${arr[@]}"
echoargs ${arr[*]}
echoargs "${arr[*]}"

When I run that, I get the output:

$ echoargs() { echo $#; printf '[%s]\n' "$@"; }
$ arr=("a" "b  c" "  d  e  f  " " multiple
>         lines too")
$ echoargs ${arr[@]}
9
[a]
[b]
[c]
[d]
[e]
[f]
[multiple]
[lines]
[too]
$ echoargs "${arr[@]}"
4
[a]
[b  c]
[  d  e  f  ]
[ multiple
        lines too]
$ echoargs ${arr[*]}
9
[a]
[b]
[c]
[d]
[e]
[f]
[multiple]
[lines]
[too]
$ echoargs "${arr[*]}"
1
[a b  c   d  e  f    multiple
        lines too]
$ 

Basically, the "${arr[@]}" form preserves the internal spacing of the elements of the array. Both the unquoted forms lose all the internal spacing information and split the array elements at sequences of one-or-more spaces. The "${arr[*]}" notation preserves internal spacing, but combines all the elements to make a single string, with a space between value.

You use the one that suits your needs, but usually the "${arr[@]}" notation is the correct one to use.

Upvotes: 0

William Pursell
William Pursell

Reputation: 212594

There's really nothing all that magical happening, it's just quoting.

for i in "q ${arr[@]} q" is the same as for i in "q ""${arr[@]}"" q" which is the same as for i in "q ""a b" "c d" "e f"" q" which is the same as for i in "q a b" "c d" "e f q"

echoargs ${arr[@]} is the same as echoargs a b c d e f

echoargs "${arr[@]}" is the same as echoargs "a b" "c d" "e f"

Upvotes: 2

Related Questions