In the answer to this question about comments in shell scripting, it is indicated that the : is a null command that explicitly does nothing (but is not to be used for comments).

What would be the utility of a command that does absolutely nothing?


I typically use true in loops; I think it's more clear:

while true; do

The one place I've found that : is really handy is in case statements, if you need to match something but don't want to actually do anything. For example:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
| improve this answer | |
  • 3
    I agree. true for a condition, : for a NOP. – jw013 Apr 27 '12 at 20:34
  • 1
    bash accepts case a in a ) ;; esac. Are there some shells which don't accept this? – Kaz Apr 28 '12 at 0:00
  • 1
    @Kaz: According to the POSIX shell grammar, case ${var} in value);; *) do_something;; esac is acceptable. The : command is not needed for empty cases. – Richard Hansen May 7 '12 at 18:47
  • The part about using true seems like a non-sequitur without reading some of the other answers first. – jamesdlin Apr 9 at 0:17

Originally, it was used to determine that it was a Bourne shell program, as opposed to C compiled program. This was before shebang and multiple scripting languages (csh, perl). You can still run a script starting with just ::

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

It will generally run the script against $SHELL (or /bin/sh).

Since then, the main use is to evaluate the arguments. I still use:

: ${EDITOR:=vim}

to set a default value in a script.

| improve this answer | |

: is useful for writing loops that must be terminated from within.

while :

This will run forever unless break or exit is called, or the shell receives a terminating signal.

| improve this answer | |
  • 4
    I feel that while true; do ...; done communicates intentions to the reader better than while :; do ...; done – Richard Hansen May 7 '12 at 18:31

When you want an "unless" statement in shell scripting, you either use a "not" condition, which can look goofy for some of the tests, or you use ':' in the true-clause, with real code in the false-clause.

if [ some-exotic-condition ]
    # Real code here

The "exotic condition" could be something you don't want to negate, or that's just a lot clearer if you don't use "negative logic".

| improve this answer | |
  • 1
    It also shows up in scripts generated by autoconf because it's much easier to add a default : for empty branches than it is to figure out how to reverse the condition. – Dietrich Epp Apr 27 '12 at 22:11
  • 3
    I can't see how sticking in a ! in front of [ some-exotic-condition ] is goofy, but a superfluous : else after it is not goofy. – Kaz Apr 28 '12 at 0:02
  • @Kaz has a good point. Let's keep in mind that coming up with exotic conditions is difficult at best. If you have to negate all of it, that's one thing, but it might just make the condition less clear. Does a '!' negate the whole condition, or just the first term? Best to have a ':' true clause sometimes. – Bruce Ediger May 3 '12 at 15:18
  • The ! token negates an entire command pipe element. while ! grep ... ; do ... done or if ! [ ... ] ; then ... fi. It's basically external to the test/[] syntax. See: pubs.opengroup.org/onlinepubs/9699919799/utilities/… – Kaz May 3 '12 at 17:49

I've only ever used this in addition to the # character for temporarily commenting out a line, in a situation in which commenting out the line produces a syntax error, due to a defect in the shell grammar of not allowing an empty sequence of commands:

if condition ; then
    :# temporarily commented out command

Without the : we have a missing command sequence, which is a syntax error.

| improve this answer | |

There are two cases where I find : useful:

Default variable assignments


# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

This is a convenient way to allow users of your shell script to override a setting without editing the script. (However, command-line arguments are better because you don't run the risk of unexpected behavior if the user coincidentally has the variable you use in their exported environment.) Here's how the user would override the setting:

VAR="other value" ./script

The ${VAR=value} syntax says to set VAR to value if VAR isn't already set, then expand to the value of the variable. Since we don't care about the value of the variable just yet, it is passed as an argument to the no-op command : to throw it away.

Even though : is a no-op command, expansion is performed by the shell (not the : command!) before running the : command so the variable assignment still occurs (if applicable).

It would also be acceptable to use true or some other command instead of :, but the code becomes harder to read because the intention is less clear.

The following script would also work:


# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

But the above is much harder to maintain. If a line using ${VAR} is added above that printf line, the default assignment expansion has to be moved. If the developer forgets to move that assignment, a bug is introduced.

Something to put in an empty conditional block

Empty conditional blocks should generally be avoided, but they're sometimes useful:

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors

Some people argue that having an empty true if block can make code easier to read than negating the test. For example:

if [ -f foo ] && bar || baz; then

is arguably easier to read than:

if ! [ -f foo ] || ! bar && ! baz; then

However I believe there are a few alternative approaches that are better than an empty true block:

  1. Put the condition in a function:

    exotic_condition() { [ -f foo ] && bar || baz; }
    if ! exotic_condition; then
  2. Put the condition inside curly braces (or parentheses, but parentheses spawn a subshell process and any changes made to the environment inside the subshell won't be visible outside the subshell) before negating:

    if ! { [ -f foo ] && bar || baz; } then
  3. Use || instead of if:

    [ -f foo ] && bar || baz || {

    I prefer this approach when the reaction is a simple one-liner, such as asserting conditions:

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    [ -f foo ] && bar || baz || fatal "condition not met"
| improve this answer | |

In the old pre-bourne shell in ancient versions of UNIX, the : command was originally intended for specifying labels for goto (it was a separate command which winds the input to where the label is found, so labels couldn't be a separate syntax that the shell knows about. if was also a separate command.) It soon became used for comments, before there was a comment syntax (# was used for backspace) and these days is around for compatibility as much as anything.

| improve this answer | |

The ":" shell command exists because in the original v1 shell, the Thompson shell, ":" introduced a label that was potentially the target of a goto command.

The Wikipedia Thompson shell article notes that:

The shell's design was intentionally minimalistic; even the if and goto statements, essential for control of program flow, were implemented as separate commands.

V1 Unix source contains that of a standalone goto command. It's got a main() function making it a standalone program. It appears to read through stdin until it finds a ":" character, then it reads zero or more ASCII space characters, then the label. If that's the label it currently looks for, it does an lseek() on stdin.

My other answer to this question is incorrect. I'm not deleting it because it contains a common use of ":" in the shell.

| improve this answer | |

In addition to using it as a statement that does nothing, you can use it to comment out single statements by turning them into arguments for :.

| improve this answer | |
  • It won't be exactly a comment since : echo write this line > myfile will still create an empty file. – Arcege Apr 27 '12 at 18:46
  • 5
    As explained in the link in the question, : is NOT an adequate commenting mechanism. – jw013 Apr 27 '12 at 18:55

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.