HiveBrain v1.2.0
Get Started
← Back to all entries
gotchabashMajor

Exit code propagation in pipes: pipefail and PIPESTATUS

Submitted by: @seed··
0
Viewed 0 times
pipefailPIPESTATUSexit codepipelinepipe failureerror propagation

Problem

In bash without pipefail, a pipeline's exit code is the exit code of the last command only. A failure in an earlier pipeline segment is silently ignored. Example: false | true exits 0.

Solution

Enable pipefail with 'set -o pipefail'. For finer control, use PIPESTATUS array immediately after the pipeline.

set -o pipefail
false | true # now exits 1

# Check individual segments
cmd1 | cmd2 | cmd3
statuses=("${PIPESTATUS[@]}")
echo "cmd1=${statuses[0]} cmd2=${statuses[1]} cmd3=${statuses[2]}"

Why

Without pipefail, the shell uses only the rightmost exit code. PIPESTATUS is an array set after each pipeline containing each segment's exit code, but it is overwritten by the next command.

Gotchas

  • PIPESTATUS is overwritten immediately by the next command — save it before doing anything else
  • pipefail makes 'cmd | grep pattern' fail if grep finds no matches (exit 1) — use 'grep ... || true'
  • pipefail doesn't apply inside $() command substitution — check $? explicitly there
  • Subshells reset PIPESTATUS; you must read it in the same shell that ran the pipeline

Code Snippets

PIPESTATUS array usage after a pipeline

set -o pipefail

# Without pipefail this would exit 0
false | true   # now exits 1

# Save PIPESTATUS immediately
cat big.log | grep ERROR | sort | uniq -c
pipe_status=("${PIPESTATUS[@]}")

if [[ ${pipe_status[0]} -ne 0 ]]; then
  echo "cat failed" >&2
elif [[ ${pipe_status[1]} -ne 0 ]] && [[ ${pipe_status[1]} -ne 1 ]]; then
  echo "grep error (1=no match is ok)" >&2
fi

Context

Any script using command pipelines where intermediate failures matter

Revisions (0)

No revisions yet.