我正在编写一个具有多个功能的 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
在调用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)的解决方案。
答案1
在我看来,这似乎是这样的描述set -e
:
如果失败的命令是...在 && 或 || 中执行的任何命令的一部分,则 shell 不会退出列表
自由地解释“&& 列表的一部分”以包含函数调用中的每个命令。因此,即使函数内的一个简单的失败命令在&&
链中调用时也不会触发 ERR 陷阱。
如果您需要在其中一个命令失败时停止执行该函数的命令,一种可能性是将它们全部链接在一个块中:
first-step-fails() {
{
true &&
false &&
true;
} || exit 1
echo "A is executed.";
}
first-step-fails && echo "B is executed.";
...导致无输出且返回码为 1。