13

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?

Andrew Schulman
  • 8,561
  • 21
  • 31
  • 47
Matt Huggins
  • 517
  • 4
  • 13

2 Answers2

13

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.

Andrew Schulman
  • 8,561
  • 21
  • 31
  • 47
  • 1
    Why does the second example include minus signs with no default value then? Am I missing something there? – Matt Huggins Apr 02 '15 at 12:32
  • No good reason I can see. If, say, $runlevel is unset, then `${runlevel-}` substitutes an empty value for it. But just `$runlevel` automatically does the same thing, so no, I don't see any reason to write it that way. – Andrew Schulman Apr 02 '15 at 12:38
  • Thanks, I think that was my biggest source of confusion in looking at this! – Matt Huggins Apr 02 '15 at 12:59
10

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"
papo
  • 199
  • 1
  • 4