Skip to main content
replaced http://unix.stackexchange.com/ with https://unix.stackexchange.com/
Source Link
Some ancient shells had what is arguably a bug: when there were no positional arguments, `"$@"` expanded to a single field containing an empty string, rather than into no field. This led to the [workaround `${1+"$@"}`](http://www.in-ulm.de/~mascheck/various/bourne_args/) (made [famous via the Perl documentation](httphttps://unix.stackexchange.com/questions/68484/what-does-1-mean-in-a-shell-script-and-how-does-it-differ-from)). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. `/bin/sh` is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there `/usr/xpg4/bin/sh` is safe so only `#!/bin/sh` script are affected, not `#!/usr/bin/env sh` scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.
Some ancient shells had what is arguably a bug: when there were no positional arguments, `"$@"` expanded to a single field containing an empty string, rather than into no field. This led to the [workaround `${1+"$@"}`](http://www.in-ulm.de/~mascheck/various/bourne_args/) (made [famous via the Perl documentation](http://unix.stackexchange.com/questions/68484/what-does-1-mean-in-a-shell-script-and-how-does-it-differ-from)). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. `/bin/sh` is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there `/usr/xpg4/bin/sh` is safe so only `#!/bin/sh` script are affected, not `#!/usr/bin/env sh` scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.
Some ancient shells had what is arguably a bug: when there were no positional arguments, `"$@"` expanded to a single field containing an empty string, rather than into no field. This led to the [workaround `${1+"$@"}`](http://www.in-ulm.de/~mascheck/various/bourne_args/) (made [famous via the Perl documentation](https://unix.stackexchange.com/questions/68484/what-does-1-mean-in-a-shell-script-and-how-does-it-differ-from)). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. `/bin/sh` is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there `/usr/xpg4/bin/sh` is safe so only `#!/bin/sh` script are affected, not `#!/usr/bin/env sh` scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.
Post Merged (destination) from unix.stackexchange.com/questions/94126/should-i-use-or
added the ${1+"$@"} story, as suggested by ninjalj
Source Link
Gilles 'SO- stop being evil'
  • 838.7k
  • 198
  • 1.8k
  • 2.2k
Some ancient shells had what is arguably a bug: when there were no positional arguments, `"$@"` expanded to a single field containing an empty string, rather than into no field. This led to the [workaround `${1+"$@"}`](http://www.in-ulm.de/~mascheck/various/bourne_args/) (made [famous via the Perl documentation](http://unix.stackexchange.com/questions/68484/what-does-1-mean-in-a-shell-script-and-how-does-it-differ-from)). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. `/bin/sh` is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there `/usr/xpg4/bin/sh` is safe so only `#!/bin/sh` script are affected, not `#!/usr/bin/env sh` scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.
Some ancient shells had what is arguably a bug: when there were no positional arguments, `"$@"` expanded to a single field containing an empty string, rather than into no field. This led to the [workaround `${1+"$@"}`](http://www.in-ulm.de/~mascheck/various/bourne_args/) (made [famous via the Perl documentation](http://unix.stackexchange.com/questions/68484/what-does-1-mean-in-a-shell-script-and-how-does-it-differ-from)). Only older versions of the actual Bourne shell and the OSF1 implementation are affected, none of its modern compatible replacements (ash, ksh, bash, …) are. `/bin/sh` is not affected on any system that was released in the 21st century that I know of (unless you count Tru64 maintenance release, and even there `/usr/xpg4/bin/sh` is safe so only `#!/bin/sh` script are affected, not `#!/usr/bin/env sh` scripts as long as your PATH is set up for POSIX compliance). In short, this is a historical anecdote that you don't need to worry about.
Source Link
Gilles 'SO- stop being evil'
  • 838.7k
  • 198
  • 1.8k
  • 2.2k

Short answer: use "$@" (note the double quotes). The other forms are very rarely useful.

"$@" is a rather strange syntax. It is replaced by all the positional parameters, as separate fields. If there are no positional parameters ($# is 0), then "$@" expands to nothing (not an empty string, but a list with 0 elements), if there is one positional parameter then "$@" is equivalent to "$1", if there are two positional parameters then "$@" is equivalent to "$1" "$2", etc.

"$@" allows you to pass down the arguments of a script or function to another command. It is very useful for wrappers that do things like setting environment variables, preparing data files, etc. before calling a command with the same arguments and options that the wrapper was called with.

For example, the following function filters the output of cvs -nq update. Apart from the output filtering and the return status (which is that of grep rather than that of cvs), calling cvssm on some arguments behaves like calling cvs -nq update with these arguments.

cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }

"$@" expands to the list of positional parameters. In shells that support arrays, there is a similar syntax to expand to the list of elements of the array: "${array[@]}" (the braces are mandatory except in zsh). Again, the double quotes are somewhat misleading: they protect against field splitting and pattern generation of the array elements, but each array element ends up in its own field.

"$*" always expands to one word. This word contains the positional parameters, concatenated with a space in between. (More generally, the separator is the first character of the value of the IFS variable. If the value of IFS is the empty string, the separator is the empty string.) If there are no positional parameters then "$*" is the empty string, if there are two positional parameters and IFS has its default value then "$*" is equivalent to "$1 $2", etc.

$@ and $* outside quotes are equivalent. They expand to the list of positional parameters, as separate fields, like "$@"; but each resulting field is then split into separate fields which are treated as file name wildcard patterns, as usual with unquoted variable expansions.

For example, if the current directory contains three files bar, baz and foo, then:

set --         # no positional parameters
for x in "$@"; do echo "$x"; done  # prints nothing
for x in "$*"; do echo "$x"; done  # prints 1 empty line
for x in $*; do echo "$x"; done    # prints nothing
set -- "b* c*" "qux"
echo "$@"      # prints `b* c* qux`
echo "$*"      # prints `b* c* qux`
echo $*        # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done  # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done  # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done    # prints 4 lines: `bar`, `baz`, `c*` and `qux`