"${1-}" vs "$1"
The code for git bash completion, specifically the function __gitcomp
, uses parameter expansions like "${1-}"
. This appears to be similar to "$1"
. What is the difference?
Also: where is this documented in the bash
man开发者_运维知识库ual?
First, recall that ${foo-bar}
expands to the value of foo
, like $foo
or ${foo}
, except that if foo
is unset, ${foo-bar}
expands to bar
($foo
expands to the empty string if foo
is unset). There is a more often-used variant of this syntax, ${foo:-bar}
, which expands to bar
if foo
is unset or empty. (This is explained in the manual if you look closely enough: search for :-
, and note the sentence “Omitting the colon results in a test only for a parameter that is unset.” above.)
For a positional parameter $1
, ${1-bar}
expands to bar
if $1
is unset, that is, if the number of positional parameters is less than 1. Unless the positional parameters have been changed with set
or shift
, this means that the current function, or if not applicable the current script, has no parameter.
Now when bar
is empty, ${1-}
looks like a useless complication: the expansion is that of $1
, except that when $1
is unset, the expansion is empty, which it would be anyway. The point of using ${1-}
is that under set -u
(a.k.a. set -o nounset
), a plain $1
would result in an error if the parameter was unset, whereas ${1-}
always successfully expands to the empty string if $1
is unset.
echo "${foo-default}"
Prints $foo, if foo is defined, and 'default', if foo is undefined. So I conclude
"${1-}"
is empty, if the first argument to the script is not defined.
The Bash reference manual §3.5.3 Shell Parameter Expansion says:
When not performing substring expansion, using the form described 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. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.
${parameter:-word}
If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.
(Emphasis added.)
If the ${1-}
appears inside double quotes in the shell script, it is really a not particularly useful way of writing "$1"
. If $1
is not defined, then both "${1-}"
and "$1"
expand to an empty argument; if $1
is defined but empty, they also both expand to an empty argument; and otherwise, even if $1
contains spaces, it appears as one argument to the called program.
If the ${1-}
appears outside double quotes, then it still isn't useful: if $1
is undefined or empty, then the called program sees no argument (with either notation); if $1
is defined, then the called program sees one or more arguments based on the (split up) value of $1
, or it sees no argument if $1
consists only of white space.
The notation really comes into its own when there is a value of some sort after the dash. For example:
localvar=${ENVVAR1:-${ENVVAR2:-/opt/software}}
This says 'if $ENVVAR1
is set to a non-empty value (including all blanks), use it; otherwise, look at $ENVVAR2
and if it is set to a non-empty value, use it; otherwise, use the value /opt/software
'.
original answer
Managed to actually pay attention to the detail of the intro to EXPANSION
-> Parameter expansion
in the manual. The final sentence before the list of expansion cases (:-
, :+
, etc.) explains that "Omitting the colon results in a test only for a parameter that is unset." If the :
is used, those tests will be for a parameter that is either unset or null.
So:
$ unset malkovich
$ echo "${malkovich:-John} ${malkovich-Malkovich}"
John Malkovich
$ malkovich=
$ echo "${malkovich:-John} ${malkovich-Malkovich}"
John
$ echo "$malkovich"
$
Moral of the story: don't just scan the manual, RTFM.
appendix
At first glance, this answer may seem irrelevant; confused readers are advised to consider the case of echo "${malkovich-}"
and then the original form as used in echo "${1-}"
. This is an answer to my question in that it explains to myself, as well as others familiar with the :-
form of default parameter expansion, that the the colon can be omitted.
As Gilles points out, "${1-}"
is effectively the same as "$1"
unless set -u
is in effect: in that case, the provision of a default value is necessary to avoid an error in cases where the variable is unset. See Johnathan Lefler's answer for a thorough explanation of the context and syntax.
精彩评论