arraysbashvariable-expansion

bash - array expansion and function calls


SETUP:

GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin21)
Copyright (C) 2007 Free Software Foundation, Inc.

TEST:

check_this() { echo "   FIRST: {$1} SECOND: {$2} THIRD: {$3}"; }

foo=(1 2 3)
expression="${foo[@]}"
echo "via expression:"
check_this "$expression"
echo "directly:"
check_this "${foo[@]}"

OUTPUT:

via expression:
   FIRST: {1 2 3} SECOND: {} THIRD: {}
directly:
   FIRST: {1} SECOND: {2} THIRD: {3}

QUESTION(s):


Solution

    • what is happening here?
    • why does "${foo[@]}" not expand to a single string?

    Because that's the explicitly defined behavior -- and a very useful one. When an array-valued variable indexed by @ is expanded inside double quotes, the result is a separate word for each element, or nothing if there are no elements.

    • how can I make the directly case above behave the via variable case?

    By using "${foo[*]}" instead of "${foo[@]}".

    • Please, explain what a construct ${foo[*]} and ${foo[@]} actually is and what the quoting operation does to it.

    Both ${foo[*]} and ${foo[@]} represent a sequence of the elements of array-valued variable foo. They differ only with respect to their behavior when expanded inside double quotes, exactly as you are exploring.

    When expanded inside double quotes, ${foo[*]} gives you a single string containing a list of all the elements, separated by the first character in $IFS (usually a space). If there are no elements then the result is equivalent to an empty pair of quotes (""). This is approximately as if you had instead written "${foo[0]} ${foo[1]} ${foo[2]} ...".

    When expanded inside double quotes, ${foo[@]} gives you a separate string for each element. If there are no elements then the result is equivalent to nothing at all. This is approximately as if you had instead written "${foo[0]}" "${foo[1]}" "${foo[2]}" .... Of the two, this is usually the one you want in practice.

    These differences are analogous to those between $* and $@.

    Perhaps it would be a mnemonic aid to associate * with "all" and @ with "each".