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
done
It is almost equivalent to:
while true; do
date -R
sleep 1
done
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
parameter="word"
fi
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?
- It will be slightly faster because shell script interpreters don't have to spawn a new process for the built-in utility.
- It can't be a command for
exec
built-in. In other words,exec :
will fail, butexec true
will succeed. - 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
y=
z=123
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.
References
- Stack Overflow, What is the purpose of the : (colon) GNU Bash builtin?
- TLDP, Advanced Bash-Scripting Guide, 10.2 Parameter Substitution
- POSIX, The Open Group Base Specifications Issue 7, Shell & Utilities, Shell Command Language, 2.6.2 Parameter Expansion
- POSIX, The Open Group Base Specifications Issue 7, Shell & Utilities, Shell Command Language, 14 Special Builtin Utilities: Colon