What does a minus sign inside of dollar brackets of a shell script mean?
In an existing shell script, I'm seeing some variables referenced that either include or end with a minus sign. For example:
PID=${PID-/run/unicorn.pid}
and:
run_by_init() {
([ "${previous-}" ] && [ "${runlevel-}" ]) || [ "${runlevel-}" = S ]
}
What do the minus signs mean in both of these scenarios?
According to the section on "Parameter Expansion" in the bash man page, this means "use the default value if the parameter is unset." So for example,
${PID-/run/unicorn.pid}
equals $PID if $PID is set, otherwise /run/unicorn.pid.
It should be emphasized that this means an unset variable. Not an empty one.
And to put to comparison with :-
, which will use default value (the one after minus sign) if variable is unset or null (as in empty string).
Minus without a colon is not seen as often (at least not by me) and has more specific use than :-
It's not even mentioned on GNU manual and not in my man bash
, but it's described for example on tldp.
In cases where you need to substitute default value, when the variable doesn't hold sensible value. The later is more suitable.
PID=${PID-/run/unicorn.pid}
PID might have been used and later emptied using PID="" in the script. This association will than fail and PID will stay an empty string ""
PID=${PID:-/run/unicorn.pid}
PID will become "/run/unicorn.pid" if it was unset, but even if it was null ("") before.
A construct without a default value ${previous-}
is debated to be a safe-guard against someone having set -u
set -u|nounset
Treat unset variables and parameters other than the special parameters ‘@’ or ‘*’ as an error when performing parameter expansion. An error message will be written to the standard error, and a non-interactive shell will exit.
https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
set -u
[ "${previous}" ] || echo "This will fail"
[ "${previous-}" ] || echo "This works"