17

What is the point of the "null" operator in a BASH script? I understand that it is used as a placeholder following an if command when you have nothing to say, but need a command to allow the program to run properly. But what is the overall use for it? When would you use it? When does it make sense to use it?

Volker Siegel
  • 13,065
  • 5
  • 49
  • 65
Justin
  • 2,121

7 Answers7

19

It's sometimes useful to allow parameter expansions side-effects to occur.

For example, setting a default value

read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"
glenn jackman
  • 17,900
  • 2
    Could you explain symbol-by-symbol how the second line works? – Ruslan Nov 15 '14 at 08:43
  • Read about the : command and parameter expansion in the bash manual. – glenn jackman Nov 17 '14 at 00:51
  • 6
    To outline what @glennjackman is referencing, the second line calls the null command :, and ${name:="John Doe"} will be expanded, causing the assignment to take place because it is read as an argument to :.

    Without the : the shell will attempt to run "John Doe" as a command, or the value $name if it is already set

    – kjh Jul 07 '16 at 15:39
14

You can also use it for endless loops:

while : ; do 
   # ....
done
choroba
  • 9,643
  • 6
    But perhaps while true is more readable, because (a) it uses less punctuation, and (b) it is more similar to C-derived languages. – wchargin Nov 15 '14 at 01:47
12

You can use it to create a file without running a program::

: > /path/to/file

This is infinitesimally faster than touch /path/to/file (since it doesn't require running the touch program) and may be marginally more portable than just plain

> /path/to/file

which seems to work on many systems.  Similarly, it can be used to check whether you have write access to a file:

if { : >> /path/to/file;} 2> /dev/null
then
    echo "writeable"
else
    echo "write permission denied"
fi

although this, also, can generally be done without the :.  Caveats:

  • This doesn’t check whether the file already exists.  If it doesn’t, this will create the file if it has permission to do so.
  • If the file doesn’t exist, and your script doesn’t have permission to create it, this will report “write permission denied”.

(See the linked question for reasons why this is more reliable than if [ -w /path/to/file ].)

6

Way back, in Unix V6 and Thompson Shell, the : was actually used as part of the goto statement. According to the manual, it originally appeared in version 3 of Unix:

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.

Nowadays, in bash, it's used as a no-op operator, returning success. Indeed, if you look at the source code, you'll see that both true and : use same function, int colon_builtin(), underneath. There's no : non-builtin command, and /bin/true is actually a fairly large command for what it does.

: could be used anywhere true is used, for example in command_that_can_fail || true, though that's likely to confuse non-experts. Read more about it here.

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
3

You can use it on the positive test of an if command when you only want to do something on the negative side. For example:

if [[ True == False ]]; then
    :
else
    echo "true <> flase"
fi

Without the : bash would generate a syntax error.

This is an oversimplified example. Generally you would use such a technique in preliminary coding when you haven't written that code segment yet and just need something that doesn't generate an error.

  • Good answer, although it may not be apparent at first, that this is most useful with an actual command within the test condition, for instance if pgrep firefox >/dev/null ; then : ; else echo "Firefox not running"; fi would show error only if firefox wasn't running. In other words, when you need to do something only when command has an error. In a way this is equivalent to pgrep firefox || echo "Firefox not running", although more readable and allows more commands – Sergiy Kolodyazhnyy Jul 13 '18 at 02:24
1

I just used it in a script with SSH commands to keep the script from erroring out.

In this case, I want to see if a user can connect to a set of servers. If the connection is OK, the remote host will echo OK. If the connection fails, SSH will respond with the error. However, I want my script to exit with 0 and not the value of the SSH command if it fails. So essentially I trap the SSH error by ORing it || with the null command :. Looks like this:

#!/bin/bash
for i in $(cat servers.txt); do
    echo -n "$i "; 
    ssh user@${i} 'echo OK' || :; 
done

That way I get the output from SSH but not the error code:

....
swl06 ok
swl07 ok
swl08 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
swl09 ok
swl10 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
....
Michael J
  • 111
0

glenn jackman's answer above is correct, but here is a detailed explanation of what this operator does:

Prevents the result from being run as a command

Essentially the null operator : prevents the result of a parameter expansion from being run as a command.

Here is a step-by-step explanation of how this works.

Run a command in bash
# Runs 'curl'
curl
Define variables and run them as commands in bash
# Define variables
EXISTING_COMMAND=curl
EMPTY_COMMAND=

Runs the 'curl' command with no flags or arguments

${EXISTING_COMMAND}

Runs the empty command, effectively doing nothing

${EMPTY_COMMAND}

Reassign a variable if empty, then run it as a command
# Define variables
EMPTY_COMMAND=

Assigns 'curl' to the EMPTY_COMMAND variable, then runs 'curl'

${EMPTY_COMMAND:=curl}

Runs 'curl'

${EMPTY_COMMAND}

You don't have to pass a literal as the default. You can also use a parameter expansion, as in ${EMPTY_COMMAND:=${EXISTING_COMMAND}}

Perform an empty-coalesce chain on a variable
TARGET_VAR=
OPTION_A=
OPTION_B=

Skips OPTION_A and OPTION_B since they are empty too, then assigns 'curl'

: ${TARGET_VAR:=${OPTION_A:=${OPTION_B:=curl}}}

I do not recommend this since both OPTION_A and OPTION_B will be overwritten with curl as well.

Do NOT run a variable as a command
# Define variables
EXISTING_COMMAND=curl

Doens't do anything

: ${EXISTING_COMMAND}

Reassign a variable if empty, then do NOT run it as a command
# Define variables
EXISTING_COMMAND=curl
EMPTY_COMMAND=

Assigns 'curl' to the EMPTY_COMMAND variable

: ${EMPTY_COMMAND:=${EXISTING_COMMAND}}

echo's 'curl' as text

echo ${EMPTY_COMMAND}

: always returns 0:

As pointed out by several answers above, then : operator, when thought of as a command, will always return 0, which effectively evaluates to true when used as a conditional expression.

In general, commands conditionally return 0 to indicate successful execution, or any positive number, such as 1, to indicate that an error has occured.

Curl returning a positive value without flags and/or arguments
# Runs 'curl', then echo's 'False'
if curl ; then
    echo 'True'
else
    echo 'False'
fi
Curl returning 0 value with valid flags and arguments
# Runs 'curl --version', then echo's 'False'
if curl --version ; then
    echo 'True'
else
    echo 'False'
fi
: returning 0 value with valid flags and arguments
# Runs ':', then echo's 'True'
if : ; then
    echo 'True'
else
    echo 'False'
fi
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center. – Community Mar 24 '23 at 17:30