在 && 表达式左侧调用的函数内部出现错误而失败

在 && 表达式左侧调用的函数内部出现错误而失败

我正在编写一个具有多个功能的 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。

相关内容