Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
1  
See also What purpose does the colon built-in serve. –  jw013 Apr 27 '12 at 18:53
2  
See also this question which has an even better answer here, namely that : is required to be a built-in, while true is not, which affects the scope of variables –  Old Pro Apr 28 '12 at 0:33
    
It explicitly does nothing gracefully. –  mikeserv May 29 at 4:13

8 Answers 8

up vote 10 down vote accepted

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

while true; do
    ...
done

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 ;;
esac
share|improve this answer
2  
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
    
@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

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

while :
do
    ...stuff...
done

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

share|improve this answer
    
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

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

share|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
3  
As explained in the link in the question, : is NOT an adequate commenting mechanism. –  jw013 Apr 27 '12 at 18:55

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 ]
then
    :
else
    # Real code here
fi

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

share|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
1  
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

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.

share|improve this answer

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
fi

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

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

share|improve this answer

There are two cases where I find : useful:

Default variable assignments

#!/bin/sh

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

#!/bin/sh

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

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
    :
else
    do_something_here
fi

is arguably easier to read than:

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

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
        do_something_here
    fi
    
  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
        do_something_here
    fi
    
  3. Use || instead of if:

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

    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"
    
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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