What is the Bash Null Command?

Channel: bash
Abstract: you can use it to replace true in a bash while loop. [me@linux ~]$ while[me@linux ~]$ cp myFile myFileCopy 2>/dev/null || echo "Failed to cp"

The Bash null command, represented by a colon :, is also known as the POSIX shell colon command. This command has no effect and does absolutely nothing, hence the null command terminology. No joke. This post covers how the Bash null command works, some pitfalls to avoid, and what are some practical use cases for this noop command.

⚠️ The Bash null command is not related to testing whether a variable is 「null」 or not. Instead, see my post How to check if a variable exists or is 「null」?.

What is the Bash Null Command?

The Bash null command : is a shell builtin defined in the POSIX standard. It is there mostly for historical reason and compatibility with older shells but it can still serve a purpose in Bash today.

As defined in the Bash manual the null command : is a command builtin that will do nothing and will always succeed. The command exit status will always be 0. The POSIX standard mentions that this shell command should only expand command arguments and be used when a command is needed, as in a then condition of an if command, but no actions should be done by the command.

The null command : is very similar to the true command which also always succeeds and returns an exit status 0.

The syntax of the null command is : [argument ...].

What are the differences between the colon and true builtin commands?

The colon command (or null command) is often compared to the true builtin. While for the most part, you would observe similar behavior, there are some slight differences to be aware of.

First, the true command is a regular builtin while the : colon command is a special builtin according to the POSIX specifications. A special builtin is required to be built into the shell, the regular builtin is not guaranteed to be. So, depending on the shell used and the implementation, : colon command may be faster than true.

Second, any variables assignments specified by a special builtin command, even environment variables, will be persisted after the command executed. This is true only for shells that are fully POSIX compliant. Bash needs to run in POSIX mode using the --posix option or set -o posix to behave as such, which is not the default bash behavior.

# Use posix compatibility mode
[me@linux ~]$ set -o posix

[me@linux ~]$ envVarExample="something" true;
[me@linux ~]$ echo "$envVarExample"

[me@linux ~]$ envVarExample="something" :;
[me@linux ~]$ echo "$envVarExample"
something

Finally, another requirement is that a regular builtin must be compatible with exec. Calling exec on the null command will fail.

[me@linux ~]$ (exec :)
bash: exec: :: not found
[me@linux ~]$ (exec true)
Pitfalls To AvoidThe Bash Null Command will Expand Arguments

Since the builtin command is expected to expand arguments, anything you pass to the command will still be processed even though the command itself won’t do anything. For example, you can still use the null command to assign variables or execute other commands. This may have an adverse effect if you expect the argument to be ignored and treated as bare strings, it won’t. The Bash null command will expand its arguments and perform redirections.

[me@linux ~]$ x=1 : $((x+=1)) > myEmptyFile
[me@linux ~]$ echo $x
2
[me@linux ~]$ ls
myEmptyFile
The Bash Null Command will buffer any command output

It is not wise to run : $(someCommand). The executed command could send a large amount of output data which will then be passed as command-line arguments. This is why it is not recommended to run a command in the arguments of the null command as the output will be buffered by the shell command which can lead to some serious memory issues depending on what you are running.

If you want to ignore some command output, prefer a simple redirection: someCommand >/dev/null.

Practical Use CasesUse the Bash null command to truncate a file

Since the bash null command will do redirections, you can easily truncate a file using : >myFile syntax. This is similar to using >myFile thought the colon version is portable across shells like csh.

Use the Bash null command to do nothing in a then clause of an if statement

When using an if statement with an empty then clause you will get the following error -bash: syntax error near unexpected token `else'. A common way to solve this is to use the : in the then clause as to ignore any action in that part of the statement and only execute in the else clause. This has been the main legacy reason to use the null command as older Bourne-like shells may not have the ! or || operators leaving only the else clause of an if statement to execute an action on a non-zero exit status, such as if command; then :; else ...; fi.

The below example will try to cp a file that doesn’t exist, redirect the stderr to /dev/null, and will echo a clear user message to user on cp failure to copy. Since then require a command, we use the : colon command.

# cp command alone with error message
[me@linux ~]$ cp myFile myFileCopy
cp: cannot stat 'myFile': No such file or directory

# cp command using the null command construct
[me@linux ~]$ if cp myFile myFileCopy 2>/dev/null; then : ; else echo "Failed to cp"; fi
Failed to cp

# Equivalent using the || operator
[me@linux ~]$ cp myFile myFileCopy 2>/dev/null || echo "Failed to cp"
Failed to cp

# Equivalent using the ! operator
[me@linux ~]$ if ! cp myFile myFileCopy 2>/dev/null; then echo "Failed to cp"; fi
Use the Bash null command as a True alias for an infinite loop

Historically, the colon command came up to mitigate the fact that true didn’t exist, or if it did, it was an external command and not a builtin. Since the command always succeeds, you can use it to replace true in a bash while loop.

[me@linux ~]$ while :; do echo "this is true"; done
this is true
this is true
this is true
...
Use the Bash null command as a Block Comment

Another common use case to the null command is to leverage it for bash comments or even block comments. The important factor to consider is to quote the arguments or use the heredoc notation otherwise the arguments will be expanded and may lead to unexpected outcomes. Make sure to single quote the heredoc delimiter otherwise variables will be expanded.

[me@linux ~]$ : 'This is a single-line comment in bash'
[me@linux ~]$ : <<'COMMENT'
This is a multiline block comment in bash
using the heredoc delimiter with single quotes
COMMENT
Use the Bash null command for Debugging and Logging

You can use the xtrace bash option (using set -x) to print out all commands for debugging purposes. A standard comment using # will not be displayed while null command will be displayed and sent to stderr.

#!/bin/bash
set -x
: 'This is a debug log'
echo "Standard output"

The above bash script would produce the output as shown below.

[me@linux ~]$ bash myScript
+ : 'This is a debug log'
+ echo 'Standard output'
Standard output
[me@linux ~]$ bash myScript 2>debug.log
Standard output
[me@linux ~]$ cat debug.log
+ : 'This is a debug log'
+ echo 'Standard output'

? Read more about the shell xtrace option with my post 5 Simple Steps On How To Debug a Bash Shell Script.

Use the Bash null command to assign a variable if not already set

With the shell parameters expansion, you can assign a default value to a variable if that variable wasn’t set. For example, ${myVar:=myDefaultValue} would set the variable myVar to the default value myDefaultValue. The problem would be that parameters expansion will return the variable value, even if you don’t need it right away leading to the below error.

[me@linux ~]$ ${myVar:=myDefaultValue}
bash: myDefaultValue: command not found

[me@linux ~]$ myVar="something"
[me@linux ~]$ ${myVar:=myDefaultValue}
bash: something: command not found

You cannot simply redirect the error output to /dev/null. The problem here is that the command is being interpreted. What if the variable value was an existing command like killall or shutdown -h now?

To prevent such an issue, you can simply use the null command as shown below. The argument expansion would make sure the variable is set with the appropriate default value while not running random commands.

[me@linux ~]$ : ${myVar:=myDefaultValue}
Use the Bash null command to ensure a script argument is set

A similar option as the variable assignment example above is to use the shell parameters expansion to test if a script argument exists or exit.

#!/bin/bash
: ${1?"Error: Argument not provided"}
echo "Got $1. Success!"

The above script test for the first argument and would produce the following output when ran with and argument and without.

[me@linux ~]$ bash myScript Hello
Got Hello. Success!

[me@linux ~]$ bash myScript
myScript: line 1: 1: Error: Argument not provided

Ref From: shell-tips

Related articles