How to copy standard output and catch error code in the meantime

It is very common to display and store command output using tee utility, but taking full advantage of it requires applying slightly different error catching strategy.

Problem

The exit status of the whole pipeline will be determined by the exit code of the last command.

$ false | tee /tmp/temporary_logfile
$ echo $?
0

Solution #1

Set pipefail option, so exit status of the whole pipeline will be defined as the value of the rightmost command that returned non-zero exit code.

I have placed commands between parentheses to execute these in a subshell environment, so defined option do not remain in effect after the subshell completes.
$ (set -o pipefail; false | tee /tmp/temporary_logfile)
$ echo $?
1

This solution is sufficient for simple cases where you execute a single command and copy its output to a file. I am using it most of the time.

Solution #2

This solution is suitable for advanced cases where you use multiple commands and want to verify exit status for each command in the pipeline, which is especially useful inside custom-built shell scripts.

It uses PIPESTATUS array variable that contains a list of exit status values from the processes in the most recently executed pipeline.

$ false | nonexistent | command | tee /tmp/1
$ echo ${PIPESTATUS[@]}
1 127 0 0

More detailed description.

$ false | nonexistent | command | tee /tmp/1
$ echo -e "false: ${PIPESTATUS[0]}\nnonexistent: ${PIPESTATUS[1]}\ncommand: ${PIPESTATUS[2]}\ntee /tmp/1: ${PIPESTATUS[3]}"
false: 1
nonexistent: 127
command: 0
tee /tmp/1: 0
Milosz Galazka's Picture

About Milosz Galazka

Milosz is a Linux Foundation Certified Engineer working for a successful Polish company as a system administrator and a long time supporter of Free Software Foundation and Debian operating system. He is also open for new opportunities and challenges.

Gdansk, Poland https://sleeplessbeastie.eu