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
manual?
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
manual?
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.
${parameter:-word}
does this, and doesn't mention the form without the colon, ${parameter-word}
. But it appears both work just fine. I'd be curious to see documentation/explanation as well! –
Jimmy set -u
was in effect. –
Shuttlecock 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
'.
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.
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.
:-
in parameter expansion but didn't realize that the colon could be omitted. Although it doesn't actually address the logic of using this form in the git completion function, that wasn't really my question. In any case, this answer as written is liable to be confusing to people who are not familiar with the :-
form; I guess I'll edit it. –
Underfeed © 2022 - 2024 — McMap. All rights reserved.