bash default/alternate values

Many people are familiar with the bourne shell constructs for default or alternate values, but there’s a detail that I suspect most people don’t know: the semantic difference between the bash and bourne shell syntax. Here is the summary:

${var-word}    # insert $var, or default value if var is unset
${var+word}    # insert alternate value if var is set
${var:-word}   # insert $var, or default value if var is unset or null
${var:+word}   # insert alternate value if var is set and non-null

Do you see the difference between these? The first two are classic bourne shell syntax, the second two are bash additions (they’re also present in most bourne shell derivatives, including posix shell). The semantic difference is that the first two only check for the existence of the variable, but the second two additionally check that it has non-zero length.

Here is an example of when the older bourne shell syntax is useful. Imagine you have a configuration file in shell syntax, so you’re going to source it into the current shell to pick up the variable settings. Something like this, which happens to work because Gentoo’s /etc/make.conf is valid shell syntax:

source /etc/make.conf

You might like to know if GENTOO_MIRRORS is set by the environment or by the configuration file, even if it was set to a null string. If it is unset after consulting both sources, we’ll call that an error. Here’s one way you could do it:

if [[ -z ${GENTOO_MIRRORS+set} ]]; then
    source /etc/make.conf
fi
if [[ -z ${GENTOO_MIRRORS+set} ]]; then
    echo "Error: GENTOO_MIRRORS not found in environment or /etc/make.conf" >&2
    exit 1
fi