What does ${1+"$@"} mean in a shell script, and how does it differ from "$@"?

That's for compatibility with the Bourne shell. The Bourne shell was an old shell that was first released with Unix version 7 in 1979 and was still common until the mid 90s as /bin/sh on most commercial Unices.

It is the ancestor of most Bourne-like shells like ksh, bash or zsh.

It had a few awkward features many of which have been fixed in ksh and the other shells and the new standard specification of sh, one of which is this:

With the Bourne shell (at least those variants where it has not been fixed): "$@" expands to one empty argument if the list of positional parameters is empty ($# == 0) instead of no argument at all.

${var+something} expands to "something" unless $var is unset. It is clearly documented in all shells but hard to find in the bash documentation as you need to pay attention to this sentence:

When not performing substring expansion, using the forms documented below, bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset.

So ${1+"$@"} expands to "$@" only if $1 is set ($# > 0) which works around that limitation of the Bourne shell.

Note that the Bourne shell is the only shell with that problem. Modern shs (that is sh conforming to the POSIX specification of sh (which the Bourne shell is not)) don't have that issue. So you only need that if you need your code to work on very old systems where /bin/sh might be a Bourne shell instead of a standard shell (note that POSIX doesn't specify the location of the standard sh, so for instance on Solaris before Solaris 11, /bin/sh was still a Bourne shell (though did not have that particular issue) while the normal/standard sh was in another location (/usr/xpg4/bin/sh)).

There is a problem in that perlrun perldoc page in that $0 is not quoted though.

See http://www.in-ulm.de/~mascheck/various/bourne_args/ for more information.


There is a difference between:

command ""

and

command

In one, you are passing one argument that is an empty string. In the second, there are zero arguments passed.

For both, "$@" will equate to the same thing: "". But using ${1:+"$@"} would be "" for the first and no arguments passed for the second, which was the intent.

This becomes important if you are doing something the script below, called sshwrapper, which you call with an optional command or no arguments to get an interactive shell.

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" "$@"

This would attempt to run "" on the remote host (which just returns), it would not be an interactive shell.

: sshwrapper [command]
exec /usr/bin/ssh "${HOSTNAME:-localhost}" ${1:+"$@"}

Would start an interactive shell on the remote host because the exec would correctly interpret the variable as nothing, not an empty string.

Read up on the usage of "${parameter:+word}" ("Use Alternate Value") and similar variable expansion strings in the bash manual pages.

Tags:

Shell

Bash

Perl