14

I am looking at a script that has:

if [ "${PS1-}" ]; then

That trailing - bugs me a bit because it doesn't seem to Posix or Bash standard syntax. It this some arcane syntax that has been around forever, or is it a typo? Any references to standards / docs would be appreciated.

Normally I would code it:

if [ "$PS1" ]; then

Which is more correct or is there a difference between them?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Gregor
  • 1,219
  • 10
  • 16

3 Answers3

27

The variable expansion ${parameter:-word} will use the value of $parameter if it's set and non-null (not an empty string), otherwise it will use the string word.

Omitting the : will not test if the value is empty, only whether it's unset or not.

This means that ${PS1-} will expand to the value of $PS1 if it's set, but to an empty string if it's empty or unset. In this case, this is exactly the same as ${PS1:-} as the string after - is also empty.

The difference between "${PS1-}" and "$PS1" is subtle, as @Rakesh Sharma notes: both will expand to the value of $PS1, or to an empty string if it is unset. The exception is when set -u is active, in which case expanding unset variables would cause an error. The (empty) default value set by"${PS1-}" circumvents this, expanding an unset PS1 to the empty string without error.

This is standard syntax (originated in the Bourne shell in the late 70s), as are a couple of other, similar expansions.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • And since it was quoted, it's the same as `"$PS1"`, since if `PS1` is empty, it is empty, and the quotes keep the word from disappearing completely. – ilkkachu Mar 17 '17 at 13:57
  • 4
    So long as the `set -u` is not in effect. When the nounset option is on, then "$PS1" => gives error. "${PS-}" won't. –  Mar 17 '17 at 14:00
12

This is definitely POSIX syntax. Paraphrasing:

Using ${parameter-word}, if parameter is

  • set and not null, then substitute the value of parameter,
  • set but null, then substitute null, and
  • unset, then substitute word.

Example session:

$ echo "${parameter-word}"
word
$ parameter=
$ echo "${parameter-word}"

$ parameter=value
$ echo "${parameter-word}"
value

"Null" here simply means the empty string. There is no special null value in POSIX shells, in contrast to SQL, for example.

This is also documented in the "Parameter Expansion" section of man bash.

l0b0
  • 50,672
  • 41
  • 197
  • 360
  • 1
    I guess the bash and dash man-pages are incomplete, because they don't mention this syntax (odd)! – Gregor Mar 17 '17 at 14:02
  • 1
    @Gregor Both manuals mention this. In the Bash manual it's in the paragraph before the list of parameter expansions, and in the Dash manual it's in the paragraph after. – Kusalananda Mar 17 '17 at 14:08
  • 1
    OK, "Omitting the colon ...." I didn't see that :( – Gregor Mar 17 '17 at 14:14
  • `zsh` is the only shell I know of that mentions the colon-free variants explicitly, rather than just making a note of what omitting the colon does. – chepner Mar 18 '17 at 00:42
  • Both the answer and `man bash` uses the term *null*, which is can be misleading. The correct term is *empty* (or *empty string* or *zero-length string*). – pts Mar 18 '17 at 07:27
  • 1
    @pts, the text in POSIX pretty much exclusively uses the term "null", which might explain its use in the man pages. – ilkkachu Mar 18 '17 at 08:33
7

The syntax:

${parameter:-word}

and a special form:

${parameter-word}

is the valid syntax in POSIX shell, means using the default value word if parameter is unset or null.


Normally, with word is empty, then:

${parameter-}

and:

$parameter

or:

${parameter}

are equivalent.

But under the effect of set -u, all unset variables cause the shell to be terminated. ${parameter-} is used to bypass that strict rule. It works in both case so yes, it's more correct way.

cuonglm
  • 150,973
  • 38
  • 327
  • 406