Use false to Test Failure Paths in Shell Scripts
You will use false to make a shell command return failure on demand, then verify how that status changes an if branch, an || fallback, and a pipeline. The command does not change files, print normal output, or need elevated privileges. Allow about ten minutes for the examples and a little longer if you are testing a real script.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a POSIX-like shell such as Bash or Dash. The installed external command used for the version checks below is GNU coreutils 9.4, from Ubuntu package coreutils 9.4-3ubuntu6.3. Your shell normally provides its own false builtin, which usually takes precedence over /usr/bin/false. That distinction matters when you ask for help or version information.
1. Confirm which false your shell will run
Start with a read-only lookup:
$ type -a false
false is a shell builtin
false is /usr/bin/false
false is /bin/false
The exact paths can differ. The first entry is the command used by an ordinary false invocation in Bash. Use the external path explicitly when you need the GNU program documented by the installed manpage:
$ command -v false
false
That output identifies the shell name rather than proving that an external file is being used. Treat type -a as the useful checkpoint.
2. Observe the failure status
Run false on its own, then immediately inspect the special parameter $?:
$ false
$ printf 'exit status: %s\n' "$?"
exit status: 1
There is normally no output from false. Status 1 is a conventional failure status, not a shell error and not a signal termination. Any command run afterwards replaces $?, so save or print it before running another diagnostic command.
The GNU program accepts ignored command-line arguments, so this is still a deliberate failure:
$ /usr/bin/false ignored arguments
$ printf 'external status: %s\n' "$?"
external status: 1
Neither form needs sudo. The command's purpose is its exit status; it does not create, delete, or alter anything.
3. Put false in an if statement
Shell conditionals test the exit status of a command. A zero status selects the success branch, while a non-zero status selects else:
$ if false; then
> printf 'success branch\n'
> else
> printf 'failure branch\n'
> fi
failure branch
This is useful for exercising an error path without first making a real command fail. Replace false with the command or function whose failure handling you need to test once the branch itself is understood.
Checkpoint: the result is correct when only failure branch appears and the compound command finishes with status zero, because the final printf succeeded:
$ if false; then :; else printf 'handled\n'; fi
handled
$ printf 'status after handling: %s\n' "$?"
status after handling: 0
4. Test an alternative with ||
The || operator runs its right-hand command only when the left-hand command fails. This makes false a compact test double for a failed check:
$ false || printf 'fallback ran\n'
fallback ran
$ true || printf 'this is not printed\n'
The status of the whole list is the status of the command that ran last. In the first example, printf succeeds, so the list returns zero. If the fallback must itself fail, make that explicit and inspect it:
$ false || false
$ printf 'list status: %s\n' "$?"
list status: 1
A common distraction is to read || as a request to print an error. It is control flow, not logging. Add a message or diagnostic command when a human needs to see what happened.
5. Check pipeline status before relying on it
In a basic shell pipeline, the status is normally the status of the last command. Therefore this can hide the deliberate failure:
$ false | cat
$ printf 'pipeline status: %s\n' "$?"
pipeline status: 0
Bash provides pipefail to make a pipeline fail when a component fails:
$ set -o pipefail
$ false | cat
$ printf 'pipeline status with pipefail: %s\n' "$?"
pipeline status with pipefail: 1
set -o pipefail changes the current shell for the rest of that shell session. In a temporary interactive test, undo it with:
$ set +o pipefail
Do not assume another shell supports this Bash option. If a script needs pipeline failure detection, declare the shell in its shebang and test the script with that shell.
6. Avoid the set -e test trap
set -e, also called errexit, can stop a script after an unhandled non-zero status. A bare false is therefore a poor test fixture inside a script that has enabled it:
$ bash -c 'set -e; false; printf "unreachable\n"'
$ printf 'script status: %s\n' "$?"
script status: 1
Use a conditional context when the failure is expected. The shell does not treat the test command in this if as an unhandled failure:
$ bash -c 'set -e; if false; then :; else printf "expected failure handled\n"; fi'
expected failure handled
This does not make set -e a complete error policy. Its exceptions around conditionals, lists, and pipelines are easy to misread. For important scripts, handle expected failures explicitly and check the status you actually intend to accept.
7. Use GNU help and version output deliberately
The external GNU command recognises --help and --version, but still exits with status 1 because it remains the false command:
$ /usr/bin/false --version
false (GNU coreutils) 9.4
...
$ printf 'status: %s\n' "$?"
status: 1
The shell builtin can produce no help or version text for these arguments and still return 1. Use the explicit path when documenting or checking GNU-specific behaviour. Do not use a version probe as a success test: read its output and expect its failure status.
Done means
- You confirmed whether the shell resolves
falseto a builtin, an external command, or both. - You verified that
falsereturns status 1 and produces no normal output. - You exercised a failure branch with
ifor a fallback with||. - You know that a pipeline can hide an earlier failure unless the shell supports and enables
pipefail. - You kept expected failures inside explicit handling when
set -eis active.