Chapter 11Lesson 03~90 minutes

pipefail and Reliable Pipeline Failure Detection

Without `pipefail`, a successful final stage can hide a failed producer. Enabling it makes pipeline status more truthful, but production scripts still need to interpret expected statuses and understand SIGPIPE behavior.

IntermediateError handlingHands-on lab

Learning objectives

By the end of this lesson

  • Explain default pipeline status.
  • Enable and interpret pipefail.
  • Capture PIPESTATUS.
  • Recognize early-consumer SIGPIPE behavior.
  • Preserve failure through tee and command substitution.

1. Normal pipeline status hides many upstream failures

false | true
printf 'status=%d\n' "$?"

Without pipefail, the status of a pipeline is normally the status of its final command. A later success can hide an earlier failure.

2. pipefail changes the pipeline result

set -o pipefail

false | true
printf 'status=%d\n' "$?"

With pipefail, the pipeline is non-zero when any stage fails. Bash reports the status of the rightmost failing command.

3. PIPESTATUS exposes every stage status

set +e
set -o pipefail

bash -c 'exit 3' |
bash -c 'exit 7' |
bash -c 'exit 0'

statuses=("${PIPESTATUS[@]}")
printf 'stage statuses: %s\n' "${statuses[*]}"

Capture PIPESTATUS immediately. Running another command changes the array.

4. Not every non-zero stage means an infrastructure failure

set -o pipefail

if generate_data | grep -q '^READY$'; then
  printf 'ready\n'
else
  status=$?
  printf 'pipeline did not succeed status=%d\n' "$status" >&2
fi

grep status 1 means “no match,” which may be an expected business result. Pipefail exposes the failure but does not interpret it for you.

6. tee does not erase upstream failure under pipefail

set -o pipefail

if build_artifact 2>&1 | tee build.log; then
  printf 'build succeeded\n'
else
  status=$?
  printf 'build failed status=%d\n' "$status" >&2
fi

This is a common reason to enable pipefail in CI scripts that need both logs and correct failure propagation.

7. Pipelines still have process-boundary behavior

Pipefail changes status propagation, not shell-state propagation. Pipeline stages may still run in separate processes, so variable updates inside them can disappear.

8. Capture pipeline output without discarding status

set -o pipefail

if output=$(generate_inventory | normalize_inventory); then
  printf '%s\n' "$output"
else
  status=$?
  printf 'inventory pipeline failed=%d\n' "$status" >&2
  exit "$status"
fi

Test the command substitution itself so the combined pipeline status becomes explicit.

9. pipefail and errexit interact

set -e
set -o pipefail

producer | transformer | consumer
printf 'only reached if the pipeline succeeds\n'

With both enabled, an unhandled pipeline failure may terminate the shell. The same grammar-context caveats from errexit still apply.

10. Sometimes a temporary file is easier to reason about

When you need per-stage diagnostics, retries, multiple consumers, or forensic evidence, a linear sequence with checked temporary artifacts can be clearer than one long pipeline.

11. Hands-on lab: reliable CI pipeline status

mkdir -p "$HOME/devops-academy/bash/chapter11/lesson03"
cd "$HOME/devops-academy/bash/chapter11/lesson03"

set -o pipefail

generate() {
  printf '%s\n' INFO READY ERROR
  return 0
}

if generate |
   grep -v '^INFO$' |
   tee filtered.log |
   grep -q '^READY$'; then
  printf 'gate=PASS\n'
else
  status=$?
  printf 'gate=FAIL status=%d\n' "$status" >&2
fi

printf '%s\n' '--- filtered log ---'
cat filtered.log

Verification checklist

12. Knowledge check

Question 1. What status does a normal pipeline report by default?

Question 2. What does pipefail change?

Question 3. What does PIPESTATUS contain?

Question 4. Why can head create a surprising pipefail result?

13. Summary

pipefail prevents later success from hiding earlier pipeline failure, but it does not understand domain semantics. Interpret expected statuses explicitly, capture PIPESTATUS immediately when needed, and watch for early-closing consumers that intentionally cause SIGPIPE.

14. Further reading

  • GNU Bash Reference Manual — Pipelines and pipefail.
  • GNU Bash Reference Manual — PIPESTATUS.
  • Linux pipe(7) and signal documentation.
  • ShellCheck documentation — pipeline status handling.
Next lesson

trap, Cleanup, and Signal-Aware Scripts

Continue Chapter 11 by making Bash failure behavior more explicit and predictable.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.