bash: $@ vs “$@”

Brad Fitz’s tweet about how bash treats $@ vs “$@” had me curious. The man page explanation is confusing but indicates these are different.

When the expansion occurs within double quotes, each parameter expands to a separate word. That is, “$@” is equivalent to “$1” “$2

So what does this mean in practice? Some code:

#!/usr/bin/python
"Print out how many command line arguments there are"
import sys
print "%d %r" % (len(sys.argv)-1, sys.argv[1:])
#!/bin/bash
echo With Quotes
./printargs.py "$@"

echo Without Quotes
./printargs.py $@
$ ./quote.sh foo "bar baz"
With Quotes
2 ['foo', 'bar baz']
Without Quotes
3 ['foo', 'bar', 'baz']

To me the quoted “$@” does what I expect; do its best to pass the arguments along verbatim, as the shell script was invoked. That rewards some advice I learned 20 years ago to just always quote “$@” in shell scripts and the right thing would happen. But if I think about it harder I get confused. For matters of shell quoting and expansion, best not to think too hard.

Update: interesting tweet from Eric Fischer

the problem is that “$@” is “” when there are no args. Magic ${1+”$@”} is “$@” when $#>0, nothing when 0