Skip to main content
In this guide, we’ll dive into how Unix-like shells handle pipelines, why errors can be hidden, and how to enforce early exits using set -o pipefail. You’ll learn best practices for robust Bash scripting and see practical examples.

How Pipelines Work

When you connect commands with a pipe (|), each command’s standard output (stdout) feeds into the next command’s standard input (stdin). However, if a middle command writes to standard error (stderr), that error goes straight to your terminal—even though the rest of the pipeline keeps running.
The image illustrates a "Pipe Fail" concept, showing data flow between a computer and processes using standard input (stdin), standard output (stdout), and standard error (stderr).

Behavior Without pipefail

Consider this simple pipeline:
What happens here:
  • sort fails (exit code ≠ 0) and emits an error.
  • uniq still runs (no input) and exits successfully.
  • cat file.txt prints its content.
Even though sort failed, the pipeline’s final exit status is 0, which masks the error.

Checking Exit Status

Inspect the pipeline’s return code with echo $?:
Despite the failure, you get 0. Likewise, boolean operators behave unexpectedly:
Here, echo still runs because the pipeline exit code is 0.

Enabling pipefail

To force a pipeline to return a non-zero status if any command fails, enable pipefail:
Save as set-pipefail.sh and execute:
With pipefail:
  • The pipeline returns the exit status of the rightmost failing command.
  • Subsequent commands and && branches are skipped on error.

Common Shell Options

Stack each set -o on its own line for clarity:

Adding a Guard Clause

Combine pipefail with an exit-on-failure guard:
If any pipeline stage fails, the script exits immediately with status 80.
Always choose a non-zero exit code that makes sense for your script. Avoid overlapping with common system codes.

Combining pipefail with Other Options

Here’s a script that prevents file overwrites and enforces pipeline errors:
Run it:
The second redirect fails, and because of pipefail plus the guard clause, the script exits with code 100.

Watch Video