A shell colon does nothing. Use it anyway.

I've written more shell scripts than I can count, but I still stumble upon tricks that honestly blow my mind far too often than I care to admit. Latest thing that blew my head clean off? The shell colon.

#shell

#shell

#posix

#posix

#unix

#unix

Table of Contents

In a land far-far away..

In a land far-far away..

Checking for required argumentsParameter expansion and the story of :?

Checking for required arguments

Parameter expansion and the story of :?

Parameter expansion and the story of :?

That.. other colon

That.. other colon

More colons in the limelight

More colons in the limelight

Con-colon-sion

Con-colon-sion

Frequently Asked QuestionsWhy do I need the null-command? Doesn't the expansion happen without the colon?Why use the null-command when I could do VAR=${VAR:-default-value}?

Frequently Asked Questions

Why do I need the null-command? Doesn't the expansion happen without the colon?

Why do I need the null-command? Doesn't the expansion happen without the colon?

Why use the null-command when I could do VAR=${VAR:-default-value}?

Why use the null-command when I could do VAR=${VAR:-default-value}?

In a land far-far away.. #

#

... there was once a far too cold cup of coffee next to a freshly brewed

far-too-hot one. Four different terminals where three could have been closed an

hour ago, and a shell script which I really (really) did not want to write.

Who would have thought a single colon would be the one to save the day night?

Note: Want your mind blown straight away? See more colons in the limelight.

more colons in the limelight

Checking for required arguments #

#

This is a familiar dance, it's pretty much muscle memory by this point. You have

a script, it takes a few arguments, and some of them are mandatory; alright, an

if-statement like so many times before:

Though.. what if I told you the above four lines could be replaced by just... one?

And look what happens if we refer to a variable with a proper name — it's

the same behavior as previously but easier to spot; the diagnostic includes

the name of our variable!

Parameter expansion and the story of :? #

#

There are two things going on in the previous snippet, and you are correct in

identifying that one part is using parameter expansion:

parameter expansion

The syntax ${name:?diagnostic} checks whether $name is unset or empty

— if it is, the diagnostic is printed to stderr and the shell exits with a

non-zero status, otherwise;

The syntax ${name:?diagnostic} checks whether $name is unset or empty

— if it is, the diagnostic is printed to stderr and the shell exits with a

non-zero status, otherwise;

if the variable is set, it is equivalent to $name.

if the variable is set, it is equivalent to $name.

That.. other colon #

#

So that's one colon, but what about that other one, the one who sits alone at

the beginning of the line?

: is the null-command

— a builtin that does nothing but evaluate its arguments and discard the

result.

: is the null-command

— a builtin that does nothing but evaluate its arguments and discard the

result.

null-command

: is old — it goes all the way back to the 1971 Thompson

shell where it doubled as a label and Unix's very first

comment marker.

: is old — it goes all the way back to the 1971 Thompson

shell where it doubled as a label and Unix's very first

comment marker.

[1971 Thompson

shell](https://en.wikipedia.org/wiki/Thompson_shell#Design)

label

: two eyes staring at you in the dark, with love.

: two eyes staring at you in the dark, with love.

More colons in the limelight #

#

Perhaps we have already established that there is more to : than meets the

eye, but to prove the real magic of the null-command —

here are a few usages that blew my mind.

null-command

Con-colon-sion #

#

So, if you are like me and prefer less typing (gotta go fast) — the

null-command and parameter expansion are a pair

worth studying before your coffee goes cold.

null-command

parameter expansion

And also.. isn't this — magic?

Note: The above example is safe to run locally, try it!

Frequently Asked Questions #

#

After reading a few comments online, it seems I skipped over some things worth

explaining. I will keep this section updated as questions come up.

Why do I need the null-command? Doesn't the expansion happen without the colon? #

The parameter expansion will happen regardless, but without a null-command or

similar usage the shell will treat the resulting string as a command to run.

% ${HELLO:=123}

zsh: command not found: 123

If we prefix our parameter-expansion with the null-command, the result is

discarded, but the expression is still evaluated (setting HELLO to 123).

% : ${HELLO:=123}

% echo $HELLO

123

Why do I need the null-command? Doesn't the expansion happen without the colon? #

#

The parameter expansion will happen regardless, but without a null-command or

similar usage the shell will treat the resulting string as a command to run.

If we prefix our parameter-expansion with the null-command, the result is

discarded, but the expression is still evaluated (setting HELLO to 123).

Why use the null-command when I could do VAR=${VAR:-default-value}? #

This at its core boils down to personal preference, but using our beloved

colon we can shrink the number of potential typos to one (rather than two):

: "${DATA_DIR:=/var/data}" # <- DATA_DIR mentioned once (1)

DATA_DIR="${DATA_DRI:-/var/data}" # <- oops (2)

Why use the null-command when I could do VAR=${VAR:-default-value}? #

#

This at its core boils down to personal preference, but using our beloved

colon we can shrink the number of potential typos to one (rather than two):