42

I've hacked on a lot of shell scripts, and sometimes the simplest things baffle me. Today I ran across a script that made extensive use of the : (colon) bash builtin.

The documenation seems simple enough:

: (a colon)  
     : [arguments]  

Do nothing beyond expanding arguments and performing redirections. The return status is zero.

However I have previously only seen this used in demonstrations of shell expansion. The use case in the script I ran across made extensive use of this structure:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

There were actually hundreds of greps, but they are just more of the same. No input/output redirects are present other than the simple structure above. No return values are checked later in the script.

I am reading this as a useless construct that says "or do nothing". What purpose could ending these greps with "or do nothing" serve? In what case would this construct cause a different outcome than simply leaving off the || : from all instances?

  • 10
    One possible purpose I can see is to use : as an alternative to true. Perhaps errexit is set and the author doesn't care about the exit status of some commands. – jw013 Feb 14 '12 at 18:42
  • 8
    Heh, nearly identical question on SO – jw013 Feb 14 '12 at 18:49
  • the Stackoverflow linked page is IMO a little more comprehensive (so good to read both this page and the linked page). – Trevor Boyd Smith Jan 18 at 14:01
28

It appears the :s in your script are being used in lieu of true. If grep doesn't find a match in the file, it will return a nonzero exit code; as jw013 mentions in a comment, if errexit is set, probably by -e on the shebang line, the script would exit if any of the greps fail to find a match. Clearly, that's not what the author wanted, so (s)he added || : to make the exit status of that particular compound command always zero, like the more common (in my experience) || true/|| /bin/true.

  • Duh. This was in the concept of an RPM build script, and while I didn't see any exit code checking inside the script, I forgot to consider that the parent process might be watching. – Caleb Feb 14 '12 at 20:55
  • 8
    If that's the case, I'd call it poor scripting practice. It's functionally equivalent to using true instead, but the semantic intent is much clearer with true. : is more suitable when an explicit NOP is desired. – jw013 Apr 27 '12 at 6:12
  • In my experience, this is a common practice in RPM scripts. It probably shouldn't be, but there we are. – mattdm Dec 15 '17 at 18:46
  • some purists prefer : instead of true because : is a bash built-in where as true is usually a compiled binary with more overhead. usually i use true because the code is more readable (likewise I prefer to use source instead of .). – Trevor Boyd Smith Jan 18 at 13:26
33

The : builtin is also useful with the Bash "assign default values" shell expansion, where the expansion is often used solely for the side effect and the value expanded is thrown away:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}
  • 2
    Came here looking for this, was baffled when I saw this pattern in a script to declare default values. – ffledgling Jun 18 '15 at 10:33
20

I can think of two places I've used : in the past.

while :
do
     shell commands
     some exit condition
done

That is a forever-loop.

function doSomethingStub {
    :
}

Put in a stub function, just to get top level flow of control correct.

One use I've seen back in the Old Days: Instead of a #!/bin/sh (or whatever) line, you'd see a : line. Some of the older Real Unix kernels or Real Unix shells would use that to mean "I'm a shell script, have sh run me". As I recall this was just when csh was making inroads as a common interactive shell.

  • @BruceEdiger: Do you have a reference to the "shecolon" line? – l0b0 Mar 22 '12 at 8:20
  • 7
    Finally found a ": at the beginning of a script" reference and explanation: faqs.org/faqs/unix-faq/faq/part3/section-16.html – Bruce Ediger Mar 22 '12 at 20:22
  • 1
    the behavior at the start with : is very strange. i found that it does indeed cause the script to be run with sh. where as when you start the script without a shebang... it tries to run the script with whatever shell is running (so if you are running bash it tries to run it as bash if you have csh then it tries to run it as csh). – Trevor Boyd Smith Jan 18 at 14:04
16

The : built-in was already in the Thompson shell — it's documented for Unix V6 in 1975. In the Thompson shell, : indicated a label for the goto command. If you never attempted to call goto on a line beginning with , that line was effectively a comment.

The Bourne shell, the ancestor of Bourne/POSIX shells as we know them, never had a goto that I know of, but retained : as a no-op command (it was already present in Unix V7).

11

I dug out an old reference: "The UNIX Programming Environment" (c) 1984 by Kernighan and Pike.

Page 147 (Shell Programming) says this:

":" is a shell built-in command that does nothing but evaluate its arguments and return "true". Instead [referring to a script example], we could have used true, which merely returns a true exit status. (There is also a false command.) But ':' is more efficient than true because it does not execute a command from the file system. [Italics/emphasis is mine.]

  • 1
    Of course, true is now a shell builtin, too, on many systems. – tripleee Feb 28 at 4:45
8

I seem to recall that early versions of the shell didn't have a comment syntax. A line starting with : (which probably would have been an actual executable, similar to /bin/true) would have been the best alternative.

Here's a man page for the ancient Thompson shell (no relation); there's no mention of any comment syntax.

  • 4
    The origin of : was in fact a label indicator for the goto command, in some ancient shell (I don't know which). A label : something could indeed be used as a comment, if there was no matching goto. The practice stuck even after goto disappeared. – Gilles Feb 15 '12 at 6:29
8

":" is handy for debugging.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

Running normally the debugfunction is never executed so sh just steps over the noop (variables and wildcards are expanded though). If more in depth debugging is required, remove the noop from the variable and debugfunction is called with whatever arguments are required.

Another handy use is as a block comment, which is a missing feature from shell syntax.

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.