If I type
into a bash shell, I get:
-bash: ::: command not found
But, only one
: results in no output. Why is this?
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It only takes a minute to sign up.Sign up to join this community
The last colon is just part of the default "not found" message:
$ x x: command not found $ :: ::: command not found
The reason a single colon produces nothing is that
: is a valid command - although it does nothing (except return
TRUE). From the
SHELL BUILTIN COMMANDS section of
: [arguments] No effect; the command does nothing beyond expanding arguments and performing any specified redirections. A zero exit code is returned.
You will sometimes see it in constructions like
while : do something done
See for example What purpose does the colon builtin serve?
:shell built-in vs non-existent
: shell built-in command exists (note the difference between external and built-in commands) which does nothing; it just returns success, just like the
true command. The
: built-in is standard and defined by the POSIX standard, where it's also known as the "null utility". It is frequently used for testing or for running infinite loops as in
while : ; do ...;done
bash-4.3$ type : : is a shell builtin
:: - two colon characters together - are interpreted as one "word" to the shell, and it assumes to be a command the user entered. The shell will go through the process of checking built-ins, then any directory in the
PATH variable for existence of that command. But there is neither a built-in
:: nor external command
::. Therefore, that produces an error.
Well, what is a typical format for an error?
<shell>: <command user typed>: error message
Thus, what you see isn't 3 colons but what you typed pasted into the standard error format.
Note also, that
: can take command-line arguments, i.e. it is legal to do:
In this case, the shell will consider that as two "words", one of which is a command and the other a positional parameter. That will also produce no error! (See also the historical note (later in this answer) about the use the of
: with positional parameters.)
Note that formatting can vary between different shells as well. For
mksh the behavior is consistent. For instance, Ubuntu's default
/bin/sh shell (which is actually
$ dash $ :: dash: 1: ::: not found
where 1 is the command number (equivalent to the line number in a script).
csh by contrast produces no error message at all:
$ csh % :: %
In fact, if you run
strace -o csh.trace csh -c ::, the trace output in
csh.trace file reveals that
csh exits with exit status 0 (no errors). But
tcsh does output the error (without outputting its name, though):
$ tcsh localhost:~> :: ::: Command not found.
In general, the first item in the error message should be the executing process or function (your shell tries to execute
::, hence the error message comes from the shell). For instance, here the executing process is
$ stat noexist stat: cannot stat 'noexist': No such file or directory
In fact, POSIX defines the perror() function, which according to the documentation takes a string argument, then outputs error message after colon, and then newline. Quote:
The perror() function shall map the error number accessed through the symbol errno to a language-dependent error message, which shall be written to the standard error stream as follows:
First (if s is not a null pointer and the character pointed to by s is not the null byte), the string pointed to by s followed by a colon and a <space>.
Then an error message string followed by a <newline>.
And the string argument to
perror() technically could be anything, but of course for clarity it's typically the function name or
By contrast, GNU has its own set of functions and variables for error handling, which a programmer can use with
stderr stream. As one of the examples on the linked page shows, something like this could be done:
fprintf (stderr, "%s: Couldn't open file %s; %s\n", program_invocation_short_name, name, strerror (errno));
The entire command file is searched for a line beginning with a : as the first non-blank character, followed by one or more blanks, and then the label. If such a line is found, goto repositions the command-file offset to the line after the label and exits. This causes the shell to transfer to the labelled line.
So you could do something like this to make an infinite loop script:
: repeat echo "Hello World" goto repeat