In an existing shell script, I'm seeing some variables referenced that either include or end with a minus sign. For example:



run_by_init() {
    ([ "${previous-}" ] && [ "${runlevel-}" ]) || [ "${runlevel-}" = S ]

What do the minus signs mean in both of these scenarios?

  • Are you sure you copied and pasted exactly as they appear in the script? Apr 2 '15 at 8:57
  • Yes, of course I did. Apr 2 '15 at 12:31

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,


equals $PID if $PID is set, otherwise /run/unicorn.pid.

  • 1
    Why does the second example include minus signs with no default value then? Am I missing something there? Apr 2 '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. Apr 2 '15 at 12:38
  • Thanks, I think that was my biggest source of confusion in looking at this! Apr 2 '15 at 12:59

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 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 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.

set -u
[ "${previous}" ] || echo "This will fail"
[ "${previous-}" ] || echo "This works"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.