Exit status 127 in pipelines with set -e and pipefail
0 reputation · 09 Dec 2020, 22:01 UTC
0 reputation · 09 Dec 2020, 22:01 UTC
This question examines how bash propagates intermediate pipeline failures when set -e and pipefail are both active, given the documented exception list for set -e and the arithmetic command (( )) status behavior. The goal is to identify predictable control-flow paths that surface silent mid-pipeline failures without relying on external tooling. Constraints include the bash manual's exception conditions for set -e (commands in if, while, or until conditions, &&/|| lists, pipeline elements except the last, !-prefixed commands) and the fact that (( )) returns exit status 1 when the evaluated expression yields zero, which can abort loops starting from zero under strict mode. The unresolved decision centers on whether explicit per-command checks or set -euo pipefail offers more reliable error detection in scripts targeting bash 4.4 and later.
Under what conditions does pipefail override set -e's exception for a failing command in a && list? Does ((i++)) from zero trigger script exit under set -euo pipefail? How does a non-zero return from command_not_found_handle interact with set -e and pipefail in a single script?
35275 reputation · 10 Dec 2020, 07:23 UTC
pipefail never overrides the set -e exception for && (or ||) lists. A failing command anywhere in such a list is exempt from triggering set -e regardless of whether pipefail is enabled.
((i++)) from zero cause a script exit under set -euo pipefail?Yes. The arithmetic command (( )) returns exit status 1 when the evaluated expression yields 0. When i starts at 0, ((i++)) evaluates to 0, so (( )) returns 1. Because this command is not placed inside an if, while, until, &&, ||, or prefixed with !, it is not exempt from set -e. Hence the script aborts before any following statements run. Adding pipefail does not change this outcome.
command_not_found_handle with set -e and pipefailWhen Bash cannot find a command, it invokes command_not_found_handle (if defined). The handler’s return value becomes the exit status of the missing command (commonly 127). If that command appears outside set -e’s exception contexts, the non‑zero status triggers an abort exactly as any other failing command would. pipefail only affects the status of pipelines; it does not alter the handling of simple commands or the set -e exception list.
pipefail does not override the && exception:
bash -c 'set -e; set -o pipefail; false | true && echo ok; echo survived'
The script prints both ok and survived, showing the pipeline failure did not abort.((i++)) aborts under strict mode:
bash -c 'set -euo pipefail; i=0; ((i++)); echo survived'
No output appears; the script exits before the echo.bash -c 'set -e; command_not_found_handle() { return 127; }; nosuchcmd; echo survived'
Again, no survived is printed.For reliable error detection in Bash 4.4+, combine set -euo pipefail with explicit checks at decision points (e.g., cmd || { echo "failed"; exit 1; }). Relying solely on set -e’s implicit aborts is fragile due to its many context‑sensitive exceptions.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.