What is the purpose of the : (colon) GNU Bash builtin?
What is the purpose of a command that does nothing, being little more than a comment leader, but is actually a shell builtin in and of itself?
It's slower than inserting a comment into your scripts by about 40% per call, which probably varies greatly depending on the size of the comment. The only possible reasons I can see for it are these:
# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done
# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command
# an alias for `true'
while : ; do command ; done
I guess what I'm really looking for is what historical application it might have had.
Solution 1:
Historically, Bourne shells didn't have true
and false
as built-in commands. true
was instead simply aliased to :
, and false
to something like let 0
.
:
is slightly better than true
for portability to ancient Bourne-derived shells. As a simple example, consider having neither the !
pipeline operator nor the ||
list operator (as was the case for some ancient Bourne shells). This leaves the else
clause of the if
statement as the only means for branching based on exit status:
if command; then :; else ...; fi
Since if
requires a non-empty then
clause and comments don't count as non-empty, :
serves as a no-op.
Nowadays (that is: in a modern context) you can usually use either :
or true
. Both are specified by POSIX, and some find true
easier to read. However there is one interesting difference: :
is a so-called POSIX special built-in, whereas true
is a regular built-in.
Special built-ins are required to be built into the shell; Regular built-ins are only "typically" built in, but it isn't strictly guaranteed. There usually shouldn't be a regular program named
:
with the function oftrue
in PATH of most systems.-
Probably the most crucial difference is that with special built-ins, any variable set by the built-in - even in the environment during simple command evaluation - persists after the command completes, as demonstrated here using ksh93:
$ unset x; ( x=hi :; echo "$x" ) hi $ ( x=hi true; echo "$x" ) $
Note that Zsh ignores this requirement, as does GNU Bash except when operating in POSIX compatibility mode, but all other major "POSIX sh derived" shells observe this including dash, ksh93, and mksh.
-
Another difference is that regular built-ins must be compatible with
exec
- demonstrated here using Bash:$ ( exec : ) -bash: exec: :: not found $ ( exec true ) $
POSIX also explicitly notes that
:
may be faster thantrue
, though this is of course an implementation-specific detail.
Solution 2:
I use it to easily enable/disable variable commands:
#!/bin/bash
if [[ "$VERBOSE" == "" || "$VERBOSE" == "0" ]]; then
vecho=":" # no "verbose echo"
else
vecho=echo # enable "verbose echo"
fi
$vecho "Verbose echo is ON"
Thus
$ ./vecho
$ VERBOSE=1 ./vecho
Verbose echo is ON
This makes for a clean script. This cannot be done with '#'.
Also,
: >afile
is one of the simplest ways to guarantee that 'afile' exists but is 0 length.
Solution 3:
A useful application for :
is if you're only interested in using parameter expansions for their side-effects rather than actually passing their result to a command.
In that case, you use the parameter expansion as an argument to either :
or false
depending upon whether you want an exit status of 0 or 1. An example might be
: "${var:=$1}"
Since :
is a builtin, it should be pretty fast.
Solution 4:
:
can also be for block comment (similar to /* */ in C language). For example, if you want to skip a block of code in your script, you can do this:
: << 'SKIP'
your code block here
SKIP
Solution 5:
It's similar to pass
in Python.
One use would be to stub out a function until it gets written:
future_function () { :; }