Colon Built-in in Bash

I came across a weird line in a shell script:

: ${parameter:=word}

It is so weird that I don't even know how to search for further information. Fortunately, I found a post after searching bash colon. It is a built-in utility which simply exits with 0. In the other words, it is almost equivalent to the true command. For example, we can write a spin loop with:

while :; do
    date -R
    sleep 1

It is almost equivalent to:

while true; do
    date -R
    sleep 1

Now, we know that the weird line is almost equivalent to:

true ${parameter:=word}

But, what does this mean? Isn't this a no-op?

To answer the question, we have to take a look on the parameter expansion. In this line, there is a parameter expansion ${parameter:=word}. It is slightly different from the normal parameter expansion ${parameter}. It comes with an extra modifier :=. The extra modifier means that shell script interpreters should assign word to parameter if parameter was unset or null. In summary, the line at the beginning of this post is equivalent to:

if [ -z "${parameter}" ]; then

More on Colon Built-in

Previously, we mentioned that the colon built-in is almost equivalent to the true command. But, what are differences between them?

  1. It will be slightly faster because shell script interpreters don't have to spawn a new process for the built-in utility.
  2. It can't be a command for exec built-in. In other words, exec : will fail, but exec true will succeed.
  3. There is a subtle difference when environment variables are passed to the colon built-in utility. However, this is not portable between different shell script interpreters. Check this post for more details.

IMO, it will be better to use colon built-in whenever possible.

More on Parameter Expansion

In addition to the := parameter expansion modifier we have mentioned earlier, there are four modifiers that we can choose: -, =, ?, and +. Their meanings are:

  • -: Use the word as the default value if the parameter is not set.
  • =: Use the word and assign the parameter if the parameter is not set.
  • ?: Print error and exit if the parameter is not set.
  • +: Use the word if the parameter is set. This is the opposite of -.

To make it clear, this is a table of the behaviors:

Modifier Parameter Set Parameter Unset
${parameter-word} Substitute parameter Substitute word
${parameter=word} Substitute parameter Assign word to parameter and substitute word
${parameter?msg} Substitute parameter Print error and exit
${parameter+word} Substitute word Substitute parameter

Besides, the : (colon) qualifier brings another dimension to these qualifiers. We can add the colon before the aforementioned modifiers. The result will be slightly different when the parameter is set to null (empty string.)

w/o colon Treat as parameter set Treat as parameter set
w/ colon Treat as parameter set Treat as parameter unset

For example:

unset x
echo "x:\t'${x-word}'\t'${x:-word}'"
echo "y:\t'${y-word}'\t'${y:-word}'"
echo "z:\t'${z-word}'\t'${z:-word}'"

This shell script will print:

x:      'word'  'word'
y:      ''      'word'
z:      '123'   '123'

Although we have gone through many parameter expansion modifiers, IMO, ${parameter:-word} and ${parameter:=word} are usually what you need.