I've been surprised with the line marked (!!)
in the following example:
log1 () { echo $@; }
log2 () { echo "$@"; }
X=(a b)
IFS='|'
echo ${X[@]} # prints a b
echo "${X[@]}" # prints a b
echo ${X[*]} # prints a b
echo "${X[*]}" # prints a|b
echo "---"
log1 ${X[@]} # prints a b
log1 "${X[@]}" # prints a b
log1 ${X[*]} # prints a b
log1 "${X[*]}" # prints a b (!!)
echo "---"
log2 ${X[@]} # prints a b
log2 "${X[@]}" # prints a b
log2 ${X[*]} # prints a b
log2 "${X[*]}" # prints a|b
Here is my understanding of the behavior:
${X[*]}
and ${X[@]}
both expand to a b
"${X[*]}"
expands to "a|b"
"${X[@]}"
expands to "a" "b"
$*
and $@
have the same behavior as ${X[*]}
and ${X[@]}
, except for their content being the parameters of the program or functionThis seems to be confirmed by the bash manual.
In the line log1 "${X[*]}"
, I therefore expect the quoted expression to expand to "a|b", then to be passed to the log1 function. The function has a single string parameter which it displays. Why does something else happen?
It'd be cool if your answers were backed by manual/standard references!
IFS
is used not just to join the elements of ${X[*]}
, but also to split the unquoted expansion $@
. For log1 "${X[*]}"
, the following happens:
"${X[*]}"
expands to a|b
as expected, so $1
is set to a|b
inside log1
.$@
(unquoted) is expanded, the resulting string is a|b
.|
as the delimiter (due to the global value of IFS
), so that echo
receives two arguments, a
and b
.That's because $IFS
is set to |
:
(X='a|b' ; IFS='|' ; echo $X)
Output:
a b
man bash
says:
IFS The Internal Field Separator that is used for word splitting after expansion ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With