18

In bash:

$ type :
: is a shell builtin
$ type true
true is a shell builtin

Looks like they are the same, but they don't give the same system trace:

$ strace :
strace: :: command not found
$ strace true
execve("/bin/true", ["true"], [/* 82 vars */]) = 0
[snip]
exit_group(0)                           = ?

I tried diffing strace bash -c : 2>:.txt and strace bash -c true 2>true.txt, but couldn't find any differences between them except for the memory locations.

In dash:

$ type :
: is a special shell builtin
$ type true
true is a shell builtin

OK, so they are not the same. help : and help true aren't very useful, and they return the same in bash and dash. Is there any practical difference at all between them, except that : saves three bytes and makes scripts less readable?

2

3 Answers 3

29

There's no real difference in behavior. Both commands do nothing and exit with a successful status. : emphasizes doing nothing; true emphasizes the successful status.

strace true works because true is both a shell builtin and an external command (/bin/true); : is only a shell builtin (there's no /bin/: -- though there could be, and probably was on very old Unix systems). In bash, try

type -a :
type -a true

The reasons that both exist are historical. If I recall correctly, some very early shells didn't have a comment syntax, so the do-nothing : command was used instead.

There is some internal difference in dash. Looking through the source, available at git://git.kernel.org/pub/scm/utils/dash/dash.git, shows some different code paths in eval.c, but I haven't been able to produce any visibly different behavior other than the word special in the output of type :.

3
  • 9
    Additionally, early versions of UNIX did not have /bin/true or /bin/false. Also the : command is sometimes used for the argument processing side effects: : ${num_times:=10}. Commented Mar 21, 2012 at 18:16
  • 8
    : was originally a label indicator, back in an ancestor of the Bourne shell that had goto. Apparently : was abused as a comment indicator and stuck. Commented Mar 21, 2012 at 23:40
  • 1
    The behavior of : as a label indicator for goto was preserved in Microsoft's pseudo-Unix command line clone, command.com, and remains in its successor cmd.exe, as does the practice of abusing :: for a line comment. Commented Jun 25, 2012 at 12:19
8

They're identical in Bash. Look at builtins/colon.def in the Bash-4.2 source code.

In your command strace true you are actually running the binary /bin/true instead of the bash built-in true.

8

The difference between the commands are that by definition : is a special built-in utility whereas true is a regular built-in utility in POSIX compliant shells.

According to POSIX specification, special built-ins are treated slightly differently in a way that:

variable assignments preceding the invocation of a special built-in utility remain in effect after the built-in completes; this shall not be the case with a regular built-in or other utility.

This can be illustrated in POSIX compliant shells as follows:

$ VAR=FOO
$ VAR=BAR :
$ echo "$VAR"
BAR
$ VAR=FOO
$ VAR=BAR true
$ echo "$VAR"
FOO

Another aspect of difference is that:

an error in a special built-in utility may cause a shell executing that utility to abort, while an error in a regular built-in utility shall not cause a shell executing that utility to abort.

Example code in action:

$ ( : > ""; echo "You won't see this!" )
sh: 1: cannot create : Directory nonexistent
$  echo "Exit code: $?"
Exit code: 2
$ ( true > ""; echo "Hello!" )
sh: 1: cannot create : Directory nonexistent
Hello!
$ echo "Exit code: $?"
Exit code: 0
4
  • That's a useful distinction. I've even seen it in action, in a very confusing form, to avoid duplication when setting default values: : "${VARIABLE:=DEFAULT_VALUE}". Commented Sep 25, 2022 at 13:47
  • @l0b0, using ${var:=value} is unrelated, though, it'd work with true also. (Try e.g. unset foo; true "${foo:=value}"; echo $foo with true vs. :.) The standard text only mentions variable assignments before the command --those that would end up as env vars for the launched command-- not expansions within the command line. Commented Sep 25, 2022 at 13:55
  • 1
    See also sh -c ': > /; echo x' vs sh -c 'true > /; echo x' and Which is more idiomatic in a bash script: `|| true` or `|| :`? Commented Sep 25, 2022 at 14:00
  • @StéphaneChazelas Updated my answer to include this aspect too. Thank you! Commented Sep 25, 2022 at 17:37

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.