设置set -o errexit后Bash脚本未在首个错误退出的原因排查
Why Command #2 Doesn't Fail as Expected
The key difference comes down to a critical exception in how Bash's errexit (set -e) option behaves when commands are part of an && or || chain. Let's break this down step by step:
First, Recap the Relevant Bash Options
errexit: Terminates the script immediately if a command exits with a non-zero status, except in specific cases we'll cover.pipefail: Makes the exit status of a pipeline equal to the last non-zero exit status of any command in the pipeline (instead of just the last command's status).
Analysis of Command #1
$ /bin/bash -c 'set -o pipefail -o errexit && my_test | ts "%FT%T"'
- We enable both
pipefailanderrexitfirst. - When
my_testruns:- The
ltt -ycommand fails (non-zero exit code). Sinceerrexitis active, this immediately terminatesmy_test(the rest of the function's commands don't run), somy_testexits with the same non-zero code asltt. - With
pipefailenabled, the entire pipelinemy_test | tsinherits that non-zero exit code. - This pipeline is the final command in the script and is not part of an
&&/||chain. Soerrexitkicks in, terminating the entirebash -cscript immediately—hence why Command #1 fails as expected.
- The
Analysis of Command #2
$ /bin/bash -c 'set -o pipefail -o errexit && my_test | ts "%FT%T" && date +%s'
- Again, we enable
pipefailanderrexit. - The pipeline
my_test | tsfails (same non-zero exit code as Command #1). - Here's the critical difference: this pipeline is part of an
&&chain (followed bydate +%s). Bash'serrexitoption explicitly does not terminate the script when a failing command is part of an&&or||sequence (and is not the final command in that sequence). - Since the pipeline fails, the
&&operator skips the subsequentdate +%scommand. However, because the failure is part of an&&chain,errexitdoesn't trigger an immediate exit. The script runs to completion, returning the non-zero exit code of the pipeline—but it doesn't "fail" in the sense of being terminated early like Command #1.
In Short
Command #1's pipeline is a standalone final command, so its failure triggers errexit. Command #2's pipeline is part of an && chain, which exempts it from the errexit termination rule—even though the pipeline itself fails, the script continues to run until the end.
内容的提问来源于stack exchange,提问作者Ankur Agarwal
相关产品推荐
相关产品推荐

