How to manage the expansion of empty or unset bash variables

Objective

The object of this tutorial is to learn how to modify bash behavior when expanding unset or empty variables using dedicated syntax.

Requirements

  • No special system privileges are required to follow this tutorial

Introduction

Variables expansion is one of the most common feature used in the shell: when a variable exists and is part of a command, it is “expanded”, so that is substituted by its value. The expansion of empty variables, is one of those things, that if not well managed, could cause serious damage to a system: imagine a command like this:

$ sudo rm -rf "/${dir}"

In a case like this, if the ${dir} variable is empty or not set, its expansion would produce no value, therefore the actual executed command would be:

$ sudo rm -rf /

Our system would be doomed. Dealing, or better preventing a situation like that it’s of vital importance. In this tutorial we will see how to manage the expansion of empty variables using some bash specific syntax.



Use a default value if a variable is empty or not set

The first case we take into account is when an unset or empty variable is referenced into an expansion and we want to use a fallback/default value in its place. Suppose we are referencing the non-existent $color variable as a part of the following command:

$ echo "the sky is $color"

The result of this command would be:

the sky is

As expected, since the variable is not set, nothing results from its expansion, leaving us with an unfinished sentence (and a sky without a color). No real harm in this case, of course, but how could we instruct the shell to use a default value in a case like this?

There is a syntax specifically designed to obtain this behavior, and it’s very simple:

${parameter:-word}

Here is how it works:

$ echo "the sky is ${color:-"blue"}"
the sky is blue

When using this syntax, if parameter doesn’t exist or is empty, the expansion will result in the value of word. In this case, the variable $color was not set, therefore the shell used “blue” as the result of the expansion.

It’s worth noticing that even if the expansion resulted in the value specified as a “default”, with this syntax, after the expansion takes place, the $color variable will still be unset:

$ echo "$color"

Use and also assign a new value if a variable is empty or not set

The command above returned no output, since the variable, at that point, was still not set. What if we want to use a specified value when expanding an unset or empty variable, but also assign that value to the variable after the expansion takes place? A slightly different syntax let us achieve what we want:

${parameter:=word}

Let’s see an example in which this syntax is used:

$ echo "the sky is ${color:="blue"}"
the sky is blue

Just as happened before, word has been used in the expansion, since parameter (the $color variable) was not set. In addition, word, (“blue” in this case), has also been assigned as the value to the previously unset variable. Verifying it’s very easy:

$ "the sky is $color"
the sky is blue

See? The expansion of the $color variable now results in “blue”.



Use an alternate value if a variable is set

A slightly different syntax let us obtain an even different result, here it is:

{parameter:+word}

How does it modify the behavior of the shell? When this syntax it’s used, if parameter is empty or not set, word will not be used, therefore the expansion will be empty. If, instead, the variable has a value, the result of the expansion will be word, and the value of parameter will not be changed. Let’s clarify this with some examples:

First case. The variable $color is not set, therefore the result of the expansion will be nothing:

$ echo "the sky is ${color:+"blue"}"
the sky is

Second case. The variable $color has a value: the expansion will result in the value specified at the right of :+, but the value of the $color variable will not be changed:

# Assign a value to the "color" variable
$ color="red"

# Since the variable is set, the result of the expansion will be "blue"
$ echo "the sky is ${color:+"blue"}"
the sky is blue

# The value of the "color" variable has not been changed
$ echo "$color"
red

Display an error message if a variable is empty or not set

The last kind of syntax we will examine here is:

${parameter:?word}

When using this syntax, if parameter is not set or empty, the script will exit with error. In addition, word will be sent to stderr (standard error). For the sake of this example, consider the “color” variable to be unset just as before:

# The message we specified is displayed to standard error
$ echo "the sky is ${color:?"color not set"}"
bash: color: color not set

The command exited with error and the color not set message was displayed. In case the variable was set, the result of the expansion would be its own value:

$ color="blue"
$ echo "the sky is ${color:?"color not set"}"
the sky is blue


Comments and Discussions
Linux Forum