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 || :

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, 2012 at 18:42
  • 9
    Heh, nearly identical question on SO
    – jw013
    Feb 14, 2012 at 18:49
  • 1
    the Stackoverflow linked page is IMO a little more comprehensive (so good to read both this page and the linked page). Jan 18, 2019 at 14:01

7 Answers 7


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 or empty
: "${FOO:=bar}"
  • 4
    Came here looking for this, was baffled when I saw this pattern in a script to declare default values.
    – ffledgling
    Jun 18, 2015 at 10:33

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, 2012 at 20:55
  • 9
    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, 2012 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, 2017 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 .). Jan 18, 2019 at 13:26
  • @jw013 : as true is known because of while :; do... it's extremely common knowledge abong bash users and just as good practice as ternary operators. I'm here because I saw it being used in the way @Joni is using it.
    – Ray Foss
    Sep 11, 2020 at 1:45

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), and it was commonly used for comments (an actual comment syntax with # was only added in a later version).

  • 1
    Point for informative historical background. Nov 9, 2019 at 11:01
  • 1
    Might be worth noting that the Bourne shell initially didn't have # comments which were introduced by csh. csh does still support labels (though that's with label: instead of : label, but that still means : defines an empty goto label). See also Difference between cat and '>' to zero out a file Mar 8, 2021 at 11:57

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

while :
     shell commands
     some exit condition

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. See: http://www.faqs.org/faqs/unix-faq/faq/part3/section-16.html

  • @BruceEdiger: Do you have a reference to the "shecolon" line?
    – l0b0
    Mar 22, 2012 at 8:20
  • 8
    Finally found a ": at the beginning of a script" reference and explanation: faqs.org/faqs/unix-faq/faq/part3/section-16.html
    – user732
    Mar 22, 2012 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). Jan 18, 2019 at 14:04

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.]

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

":" is handy for debugging.

DEBUGLOG=": debugfunction"

$DEBUGLOG arg1 arg2 ...

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.

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

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.

  • 6
    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. Feb 15, 2012 at 6:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .