Search code examples
shellpipeposixpipeline

How to cause a Linux pipeline to fail?


Recently I'm learning the set -e of POSIX shell on Ubuntu 14.04. My reference material is the "IEEE Std 1003.1-2008, 2016 Edition", "Shell & Utilities" chapter. From this section I see -e doesn't cause the script to quit when the command fails in a pipeline (unless the failed command is the last one in the pipeline):

The failure of any individual command in a multi-command pipeline shall not cause the shell to exit. Only the failure of the pipeline itself shall be considered.

I then wrote a simple script to confirm this behavior:

(
    set -e
    false | true | false | true
    echo ">> Multi-command pipeline: Last command succeeded."
)
(
    set -e
    false | true | false
    echo ">> Multi-command pipeline: Last command failed."
)

The "Last command succeeded" message is printed out, while the "Last command failed" message is not.

My questions are:

  • The chained commands false | true | false don't seem to be a failure of the pipeline. It's just the failure of the last command. The pipeline itself still succeeds. Am I right??
  • Is there a way to simulate a pipeline failure?? We can use false to simulate the failure of a command. Is there a similar command for a pipeline?

Solution

  • By default in bash, the success or failure of a pipeline is determined solely by the last command in the pipeline.

    You may however enable the pipefail option (set -o pipefail) and the pipeline will return failure if any command in the pipeline fails.

    Example

    This pipeline succeeds:

    $ false | true | false | true ; echo $?
    0
    

    This pipeline fails:

    $ set -o pipefail
    $ false | true | false | true ; echo $?
    1
    

    Documentation

    From man bash:

    The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.