Bash exit status used with PIPE

bashexitpipeshell-script

I am trying to understand how exit status is communicated when a pipe is used. Suppose I am using which to locate a non-existent program:

which lss
echo $?
1

Since which failed to locate lss I got an exit status of 1. This is fine. However when I try the following:

which lss | echo $?
0

This indicates that the last command executed has exited normally. The only way I can understand this is that perhaps PIPE also produces an exit status. Is this right way to understand it?

Best Answer

The exit status of the pipeline is the exit status of the last command in the pipeline (unless the shell option pipefail is set in the shells that support it, in which case the exit status will be that of the last command in the pipeline that exits with a non-zero status).

It is not possible to output the exit status of a pipeline from within a pipeline, since there is no way of knowing what that value would be until the pipeline has actually finished executing.

The pipeline

which lss | echo $?

is nonsensical since echo doesn't read its standard input (pipelines are used to pass data between the output of one command to the input of the next). The echo would also not print the exit status of the pipeline, but the exit status of the command run immediately before the pipeline.

$ false
$ which hello | echo $?
1
which: hello: Command not found.

$ true
$ which hello | echo $?
0
which: hello: Command not found.

This is a better example:

$ echo hello | read a
$ echo $?
0

$ echo nonexistent | { read filename && rm $filename; }
rm: nonexistent: No such file or directory
$ echo $?
1

This means that a pipeline may also be used with if:

if gzip -dc file.gz | grep -q 'something'; then
  echo 'something was found'
fi