Sunday, July 26, 2009

What's this Colon Doing in My Comments?

Shell comments start with '#' -- except when they start with ':'.

Before 1981, they all started with ':', and they weren't really comments, they were commands. They still are.

$ type :
: is a shell builtin
':' is a no-op. Like true, it's a command that always succeeds, and does nothing.

Since it doesn't do anything, you can give it whatever arguments you want.

: This is a command that does nothing. And, a comment.
With one wrinkle: since it's a command, the shell processes its arguments. Side-effects? You bet.

Here's a surprisingly common idiom in shell scripts. (Look through the /etc/ directory for these.)

: ${FOO:=bar}
Huh? Okay, step at a time:

  1. $FOO is the value of the variable FOO.
  2. ${FOO:-bar} has the value $FOO, unless FOO doesn't have a value. If FOO is unset or null, then the value of this typographic mess is the string, "bar".
  3. ${FOO:=bar} is like that, but it also assigns FOO the value bar as a side-effect if it didn't already have a value.
  4. So this command

: ${FOO:=bar}

sets FOO to the default value "bar", if it hasn't already been set to something else. And then, it goes on to the next line in the script, because the command itself is a no-op.

The entire purpose of that null command is the side-effect produced when the shell evaluates its arguments -- it announces a default value for $FOO.

More verbose ways to say this include these:

$ FOO=${FOO:-bar}

$ [ "$FOO" ] || FOO=bar
or even

$ if [ "$FOO" = "" ]; then FOO=bar; fi
But if you want to understand the scripts in the /etc/ directory, you need to at least recognize:

and not be intimidated by it.

Plus, knowing this lets you make sense of shell scripts that are more than 29 years old. Since this is the 40th anniversary of Unix, that seems fitting.

No comments: