我正在开发一个具有多个功能的 Bash 脚本。如果任何命令返回非零退出代码,我想退出脚本,除非在明确处理该代码的上下文中(例如在if
条件中或在||
替代之前)。为了使这更容易,我从脚本中删除了所有子 shell 的使用,并启用了我能找到的每个错误处理选项。
不幸的是,我仍然遇到一种常见的错误被抑制的模式。
如果函数中的命令返回非零退出代码,但不是函数中的最后一个命令,并且函数作为&&
表达式的第一部分被调用,则退出代码将被忽略。
#!/bin/bash
trap 'echo "Error occurred." && exit' ERR
set -o errexit; # -e
set -o errtrace; # -E
set -o pipefail;
first-step-fails() {
# These should be redundant, but are repeated to be certain and clear.
trap 'echo "Error occurred." && exit' ERR
set -o errexit; # -e
set -o errtrace; # -E
set -o pipefail;
false; # exit code 1 (failure)
true; # exit code 0 (success)
echo "A is executed.";
}
first-step-fails && echo "B is executed.";
A is executed.
B is executed.
我没想到任何一个echo
s 都会在调用false
.
如果未在&&
表达式中调用该函数,则会捕获错误:
#!/bin/bash
trap 'echo "Error occurred." && exit' ERR
set -o errexit; # -e
set -o errtrace; # -E
set -o pipefail;
first-step-fails() {
# These should be redundant, but are repeated to be certain and clear.
trap 'echo "Error occurred." && exit' ERR
set -o errexit; # -e
set -o errtrace; # -E
set -o pipefail;
false; # exit code 1 (failure)
true; # exit code 0 (success)
echo "A is executed.";
}
first-step-fails ### && echo "B is executed.";
Error occurred.
如果失败是函数的最后一步,则错误不会被捕获,但函数当然会传递其非零退出状态并抑制外部echo
.
#!/bin/bash
trap 'echo "Error occurred." && exit' ERR
set -o errexit; # -e
set -o errtrace; # -E
set -o pipefail;
first-step-fails() {
# These should be redundant, but are repeated to be certain and clear.
trap 'echo "Error occurred." && exit' ERR
set -o errexit; # -e
set -o errtrace; # -E
set -o pipefail;
false; # exit code 1 (failure)
### true; # exit code 0 (success)
### echo "A is executed.";
}
first-step-fails && echo "B is executed.";
(no output)
当在表达式左侧调用的函数内部调用的命令返回非零退出状态时,如何让我的 bash 脚本退出&&
?
我一直在 macOS(内置 GNU Bash 4.4.23)上进行测试,但需要一个也适用于 Alpine Linux(打包 GNU Bash 4.4.19)的解决方案。
在我看来,这个描述好像是
set -e
:自由地解释“&& 列表的一部分”以包含函数调用中的每个命令。因此,即使是函数内部的一个简单的失败命令也不会触发 ERR 陷阱——当它在
&&
链中被调用时。如果您需要在其中一个命令失败时停止执行该函数的命令,一种可能性是将它们全部链接到一个块中:
... 导致没有输出并且返回码为 1。