When chaining commands in Bash using the pipe |
separator, the commands execute in sequence, with the output of the first command being used as the input to the second command.
When running a single Bash command, it is possible to detect if an error has occurred by examining the $?
built-in Bash variable directly after the command has completed. A zero 0
return value means success, a non-zero return value means that an error has occurred.
For example, trying to write output to a new file in the root of the file system.
$ echo "Create a file with one line in it" > /new-file.txt
-bash: /new-file.txt: Permission denied
$ echo $?
1
Whereas writing a file to your home path will succeed as expected.
$ echo "Create a file with one line in it" > ~/new-file.txt
$ echo $?
0
But what happens if an error occurs when executing a command within a piped list of commands? In this case, the default is for the last command to set the return value for the entire command chain.
$ cat /new-file.txt | wc
cat: /new-file.txt: No such file or directory
0 0 0
$ echo $?
0
Which doesn’t help very much if you are trying to detect when anything has gone wrong within the combined command. This can be overridden by setting the pipefail
Bash option.
$ set -o pipefail
$ cat /new-file.txt | wc
cat: /new-file.txt: No such file or directory
0 0 0
$ echo $?
1
This can be extremely useful if you regularly chain commands together, as the return value can be used to display a message to the user indicating an issue has occurred within the command chain.