set -e (Exit on Error) and Its Gotchas
In this page:
Basic Exit-on-Error Behavior
With set -e active, a script stops executing as soon as any command returns a non-zero exit status, rather than silently continuing to later lines that might depend on that command having succeeded.
Example: Basic Exit-on-Error Behavior
#!/bin/bash
(
set -e
echo "step 1"
false
echo "step 2 - never reached"
) || echo "the subshell stopped early because of set -e"
Login to try C/C++/Java/PHP code in the editor
The if-condition Exemption
A command being tested as the condition of if, while, or until is exempt from set -e, because a non-zero status there is expected and meaningful, not a bug.
Example: The if-condition Exemption
#!/bin/bash
(
set -e
if false; then
echo "unreachable"
else
echo "set -e did NOT trigger here, because false was an if-condition"
fi
echo "the subshell kept running normally"
)
Login to try C/C++/Java/PHP code in the editor
The Pipeline Exemption
Inside a pipeline, plain set -e only reacts to the exit status of the LAST command, so a failure in an earlier stage is silently ignored unless pipefail is also enabled.
Example: The Pipeline Exemption
#!/bin/bash
(
set -e
false | true
echo "reached because only the last command (true) mattered to set -e"
)
(
set -e -o pipefail
false | true
echo "unreachable with pipefail active"
) || echo "with pipefail, the earlier failure was noticed and stopped the subshell"
Login to try C/C++/Java/PHP code in the editor
Catching a set -e Failure Deliberately
Wrapping a risky command in a subshell with its own set -e, and checking the subshell's overall result with ||, lets a script demonstrate or contain a strict failure without letting it kill the whole script.
Note: Test set -e behavior in a small subshell like this before relying on it in a large script; its exemptions are easy to trip over.
Example: Catching a set -e Failure Deliberately
#!/bin/bash
(set -e; false; echo "unreached") || echo "caught: the previous command failed under set -e"
echo "the main script keeps running normally"
Login to try C/C++/Java/PHP code in the editor
- Assuming
set -ecatches every possible failure; it does NOT trigger for a failing command inside anif/whilecondition, before a&&/||, or as any-but-the-last part of a pipeline. - Being surprised a script keeps running after a failing command inside a function call used in a condition, since
set -e's exemptions apply there too. - Relying on
set -ealone for robust error handling instead of combining it with explicit checks for the specific commands that matter most.
set -emakes the script exit immediately if a command exits non-zero, instead of continuing to the next line.set -edoes NOT apply to a command being tested byif,while,until, or before&&/||— those are expected to potentially fail.- In a pipeline,
set -eonly reacts to the LAST command's exit status, unlesspipefailis also set. set -eis best combined withset -uandset -o pipefailfor more predictable strict-mode behavior.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first:
- Exit Codes and Checking $? Correctly
- set -e and set -u
- Error Handling
- set -e (Exit on Error) and Its Gotchas
- Logging
- set -u (Undefined Variables) and set -x (Trace Mode)
- Script Arguments with getopts
- trap ERR for Custom Error Handling
- Debug Mode (set -x)
- Writing a Custom Error/die Function
- Portability
- Validating Script Input and Arguments