4

I don't understand why "${ARRAY[@]}" gets expanded to multiple words, when it's quoted ("...")?

Take this example:

IFS=":" read -ra ARRAY <<< "foo:bar:baz"
for e in "${ARRAY[@]}"; do echo $e; done
foo
bar
baz

Any other variable that I expand in quotes, say "${VAR}", results in a single word:

VAR="foo bar baz"
for a in "${VAR}"; do echo $a; done
foo bar baz

Can anyone explain this to a novice Linux user?

Shuzheng
  • 4,411
  • ${array[@]} and ${array[*]} are supposed to act analogously to $@ and $*. That's a thing called "consistency". –  Jan 17 '20 at 17:27
  • The consistency extends (at least in practice) to other forms like "${@:2:4}" vs. "${array[@]:2:4}" or "${@/pat/repl}" vs "${array[@]/pat/repl}" vs. their * forms. –  Jan 17 '20 at 17:37

1 Answers1

12

Because arrays when indexed with @ and double quoted expand to a list of the elements. It's documented in man bash under "Arrays":

If the word is double-quoted, ... ${name[@]} expands each element of name to a separate word.

This behaviour is required if you don't want each element to be subject to word splitting on $IFS characters and globbing (i.e. expansion of *, ?, or [...]).

#!/bin/bash
arr=(a 'b c' d)
for el in  ${arr[@]}  ; do echo "1: $el" ; done
for el in "${arr[@]}" ; do echo "2: $el" ; done

Output:

1: a
1: b
1: c
1: d
2: a
2: b c
2: d

If you want the array expanded as a single string (with the elements of the array delimited by the first character of $IFS, by default a space), then use "${arr[*]}".

The "${arr[@]}" and "${arr[*]}" syntax for array expansion is analogous to "$@" and "$*" for the positional parameters.

choroba
  • 47,233
  • 3
    It's not really whitespace, it's characters of $IFS (SPC, TAB, NL by default) and wildcard characters. IMO, the wording is a bit misleading here. It's not useful it's required. You don't leave parameter expansions unquoted unless you want that split+glob. Split+glob on an array hardly ever makes sense, so array expansions should almost always be quoted. – Stéphane Chazelas Jan 18 '20 at 08:23
  • @StéphaneChazelas: Updated. – choroba May 04 '23 at 16:07
  • That This behaviour is required if an element contains whitespace or characters from the $IFS variable wording still doesn't make much sense. Maybe something like Without the quoting, each element would also be subject to split+glob so not do what you want if they contained characters of $IFS (not whitespace) or glob operators such as `,?or[...]`*. – Stéphane Chazelas May 04 '23 at 16:14