bash - 如何使 errexit 行为在 bash 函数中起作用

标签 bash

如何让 -e/errexit 在 bash 函数中工作,以便函数中第一个失败的命令* 导致函数返回错误代码(就像 - e 在顶层工作)。

* 不是 bool 表达式的一部分,if/elif/while/etc 等等

我运行了以下测试脚本,我希望名称中包含 f 的任何函数(即源代码中的 false 行)返回错误代码,但如果之后有另一个命令,他们就不会这样做。即使当我将函数体放入再次指定 set -e 的子 shell 中时,它也会在命令失败后盲目地继续执行该函数,而不是使用非零状态代码退出子 shell/函数。

测试的环境/解释器:

我在所有这些 envs/shell 中都得到了相同的结果,我想这是可以预料的,除非有一个有问题。

拱门:

  • bash test.sh(bash 5.1)
  • zsh test.sh (zsh 5.8)
  • sh test.sh(只是 bash 的符号链接(symbolic link))

Alpine :

  • docker run -v/test.sh:/test.sh alpine:latest sh/test.sh (BusyBox 1.34)

Ubuntu:

  • docker run -v/test.sh:/test.sh ubuntu:21.04 sh/test.sh
  • docker run -v/test.sh:/test.sh ubuntu:21.04 bash/test.sh (bash 5.1)
  • docker run -v/test.sh:/test.sh ubuntu:21.04 dash/test.sh (bash 5.1)

测试脚本

set -e

t() {
    true
}

f() {
    false
}

tf() {
    true
    false
}

ft() {
    false
    true
}

et() {
    set -e
    true
}

ef() {
    set -e
    false
}

etf() {
    set -e
    true
    false
}

eft() {
    set -e
    false
    true
}

st() {( set -e
    true
)}

sf() {( set -e
    false
)}

stf() {( set -e
    true
    false
)}

sft() {( set -e
    false
    true
)}

for test in t f tf ft _ et ef etf eft _ st sf stf sft; do
    if [ "$test" = '_' ]; then
        echo ""
    elif "$test"; then
        echo "$test: pass"
    else
        echo "$test: fail"
    fi
done

我的机器上的输出

t: pass
f: fail
tf: fail
ft: pass

et: pass
ef: fail
etf: fail
eft: pass

st: pass
sf: fail
stf: fail
sft: pass

期望的输出

无需显着更改函数本身的源代码,即不添加 if/then 或 || return 到函数中的每一行。

t: pass
f: fail
tf: fail
ft: fail

et: pass
ef: fail
etf: fail
eft: fail

st: pass
sf: fail
stf: fail
sft: fail

或者至少在一组中通过/失败/失败/失败,这样我就可以使用这种方法来编写强大的函数。

采用已接受的解决方案

通过接受的解决方案,前四项测试给出了所需的结果。其他两组没有,但无关紧要,因为这些是我自己解决该问题的尝试。根本原因是“当 if/while 条件失败时不要错误退出脚本”行为传播到条件中调用的任何函数中,而不仅仅是应用于最终结果。

最佳答案

How to make errexit behaviour work in bash functions

调用不在 if 内部的函数.

I expect any function containing f in its name (i.e. a false line in its source) to return error-code

Weeeeeell,您的期望与现实不符。这不是它的实现方式。和标志err<b>exit</b>将退出您的脚本,而不返回错误代码。

Desired output

你可以:

  • 下载 Bash 或其他 shell 源代码,或者编写您自己的源代码并实现您想要的行为。

    • 考虑扩展类似 shopt -s errexit_but_return_nonzero_in_if_contexts 的行为或者更短的东西
  • 在单独的 shell 中运行它。

    elif bash -ec "$(declare -f "$test"); $test"; then
    
  • 编写自定义可加载文件以“清除”CMD_IGNORE_RETURN当 Bash 进入 set -e 的上下文时标记应该被忽略。我认为 static COMMAND *currently_executing_command; 需要是外部的,然后只是 currently_executing_command.flags &= ~CMD_IGNORE_RETURN; .

  • 您可以做一个包装器,在其中临时禁用 errexit 并获取返回状态,但您必须在 if 之外调用它。 :

errreturn() {
    declare -g ERRRETURN
    local flags=$(set +o)
    set +e
    (
        set -e
        "$@"
    )
    ERRRETURN=$?
    eval "$flags"
}

....
        echo ""
    else
        errreturn "$test"
        if (( ERRRETURN == 0 )); then
            echo "$test: pass"
        else
            echo "$test: fail"
        fi
    fi

关于bash - 如何使 errexit 行为在 bash 函数中起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70987732/

相关文章:

bash - Windows 上的 homestead vagrant 中没有 laravel 同步文件夹

linux - 使用 shell 脚本检查文件中给定的字符串

bash - bash 中的 awk 和 printf

linux - 'grep'如何连续流?

javascript - 从 bash 脚本运行 Node : output console. 日志

linux - 将 IFS 设置为在换行符上拆分时,为什么需要包含退格键?

linux - 我如何使用linux编写基本脚本?

bash - 如何在称为条件的shell函数中可靠地处理错误?

macos - Mac OS X | Bash .bash_profile 未更新 PS1

javascript - 将简单的温度 bash 脚本转换为 javascript