shell - 如何在 shell 函数中获得 "set -e"的效果和用处?

标签 shell error-handling sh

set -e(或以 #!/bin/sh -e 开头的脚本)对于在出现问题时自动轰炸非常有用。它使我不必对每个可能失败的命令进行错误检查。

我如何在函数中获得 this 的等价物?

例如,我有以下脚本,它会在出错时立即退出,并显示错误退出状态:

#!/bin/sh -e

echo "the following command could fail:"
false
echo "this is after the command that fails"

输出符合预期:

the following command could fail:

现在我想把它包装成一个函数:

#!/bin/sh -e

my_function() {
    echo "the following command could fail:"
    false
    echo "this is after the command that fails"
}

if ! my_function; then
    echo "dealing with the problem"
fi

echo "run this all the time regardless of the success of my_function"

预期输出:

the following command could fail:
dealing with the problem
run this all the time regardless of the success of my_function

实际输出:

the following output could fail:
this is after the command that fails
run this all the time regardless of the success of my_function

(即函数忽略 set -e)

这大概是预期的行为。我的问题是:如何在 shell 函数中获得 set -e 的效果和用处?我希望能够设置一些东西,这样我就不必单独检查每个调用的错误,但脚本会在遇到错误时停止。它应该根据需要展开堆栈,直到我检查结果,或者如果我没有检查它就退出脚本本身。这就是 set -e 已经做的事情,只是它不嵌套。

我找到了 the same question在 Stack Overflow 之外询问但没有合适的答案。

最佳答案

我最终接受了这个,这显然有效。起初我尝试了导出方法,但后来发现我需要导出脚本使用的每个全局(常量)变量。

禁用 set -e,然后在启用了 set -e 的子 shell 中运行函数调用。将 subshel​​l 的退出状态保存在变量中,重新启用 set -e,然后测试 var。

f() { echo "a"; false;  echo "Should NOT get HERE"; }

# Don't pipe the subshell into anything or we won't be able to see its exit status
set +e ; ( set -e; f ) ; err_status=$?
set -e

## cleaner syntax which POSIX sh doesn't support.  Use bash/zsh/ksh/other fancy shells
if ((err_status)) ; then
    echo "f returned false: $err_status"
fi

## POSIX-sh features only (e.g. dash, /bin/sh)
if test "$err_status" -ne 0 ; then
    echo "f returned false: $err_status"
fi

echo "always print this"

您不能将 f 作为管道的一部分或作为 || 命令列表的 && 的一部分运行(除了管道或列表中的最后一个命令),或作为 ifwhile 中的条件,或其他忽略 set -e 的上下文。 此代码也不能在任何这些上下文中,因此如果您在函数中使用它,调用者必须使用相同的子 shell/save-exit-status 技巧。考虑到限制和难以阅读的语法,将 set -e 用于类似于抛出/捕获异常的语义并不真正适合一般用途。

trap err_handler_function ERR 具有与 set -e 相同的限制,因为在 set -e 的上下文中它不会因错误而触发> 不会因命令失败而退出。

您可能认为以下内容可行,但事实并非如此:

if ! ( set -e; f );then    ##### doesn't work, f runs ignoring -e
    echo "f returned false: $?"
fi

set -e 不会在 subshel​​l 内生效,因为它记得它在 if 的条件内。我认为作为一个子 shell 会改变这一点,但只有在一个单独的文件中并在其上运行一个完整的单独 shell 才会起作用。

关于shell - 如何在 shell 函数中获得 "set -e"的效果和用处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5754845/

相关文章:

jsf-2 - 从 Facelets 错误页面引用 CDI 托管 bean

bash - 当子脚本之一失败时不退出 bash 脚本

linux - 你能解释一下这个命令的作用吗

linux - bash 执行整个脚本,但如果任何中间作业失败则返回退出代码 > 0

android - 使用 Android 应用程序运行脚本

Linux 管道在特定位置的先前结果

java - 检查非法输入.nextLine Java

rest - 如何避免 Golang 服务器 (Gin Gonic) 在 INTERNAL_ERROR 上崩溃

linux - 在 Bourne Shell 中调用函数

java - 为什么我无法从脚本执行我的 java 项目?