Bash:错误的优雅功能死亡

时间:2017-01-21 01:02:14

标签: bash function shell error-handling

我正试图找到一种方法来模拟函数中set -e的行为,但仅限于该函数的范围内。

基本上,我想要一个函数,如果任何简单命令会触发set -e,它会向上返回1级。目标是将多组风险工作隔离成函数,以便我可以优雅地处理它们。

4 个答案:

答案 0 :(得分:3)

如果您希望任何失败的命令返回1,您可以通过使用|| return 1跟随每个命令来实现此目的。

例如:

false || return 1  # This will always return 1

如果没有明确的处理,我绝不会让任何命令失败。对于我的脚本,我使用的是异常处理技术,我以不返回代码的方式返回错误,并捕获所有错误(使用bash陷阱)。任何带有非零返回码的命令都会自动意味着处理不当的情况或错误,我更喜欢我的脚本在发生这种情况时立即失败。

答案 1 :(得分:0)

警告:我强烈建议不要使用这种技术。如果在子shell环境中运行该函数,则几乎可以获得所需的行为。考虑:

#!/bin/bash

foo() (  # Use parens to get a sub-shell
        set -e  # Does not impact the main script
        echo This is executed
        false
        echo This should *not* be executed
)

foo  # Function call fails, returns 1
echo return: $?

# BUT: this is a good reason to avoid this technique
if foo; then  # Set -e is invalid in the function
        echo Foo returned 0!!
else
        echo fail
fi
false    # Demonstrates that set -e is not set for the script
echo ok

答案 2 :(得分:0)

好像你正在寻找“嵌套异常”,就像Java给出的那样。对于您确定范围的要求,如何在函数开头执行set -e并确保在返回之前运行set +e

另一个不高效或方便的想法是在子shell中调用你的函数:

# some code

(set -e; my_function)
if [[ $? -ne 0 ]]; then
  # the function didn't succeed...
fi

# more code

在任何情况下,请注意set -e 是处理shell脚本错误的最佳方式。有太多问题使它变得非常不可靠。请参阅以下相关帖子:

我需要在生产环境中长时间存在的大型脚本采用的方法是:

  • 创建一个函数库来完成所有标准的工作
  • 该库将包含每个标准操作的包装(例如mvcpmkdirlnrm等。将仔细验证参数并处理异常
  • 发生异常时,包装器将以明确的错误消息退出
  • 退出本身可能是一个库函数,有点像这样:

-

# library of common functions

trap '_error_handler' ERR
trap '_exit_handler'  EXIT
trap '_int_handler'   SIGINT

_error_handler() {
  # appropriate code
}
# other handlers go here...
#

exit_if_error() {
  error_code=${1:-0}
  error_message=${2:-"Uknown error"}

  [[ $error_code == 0 ]] && return 0  # it is all good

  # this can be enhanced to print out the "stack trace"
  >&2 printf "%s\n" $error_message

  # out of here
  my_exit $error_code
}

my_exit() {
  exit_code=${1:-0}
  _global_graceful_exit=1  # this can be checked by the "EXIT" trap handler
  exit $exit_code
}

# simple wrapper for cp
my_cp() {
  # add code to check arguments more effectively
  cp $1 $2
  exit_if_error $? "cp of '$1' to '$2' failed"
}

# main code

source /path/to/library.sh

...
my_cp file1 file2
# clutter-free code

这有效地使用trapERREXIT事件采取行动,这将是编写可靠shell脚本的好方法。

答案 3 :(得分:0)

进行更多研究,我在Google的Shell Style Guide中找到了一个我更喜欢的解决方案。这里有一些非常有趣的建议,但我认为为了便于阅读,我会选择这个:

if ! mv "${file_list}" "${dest_dir}/" ; then
  echo "Unable to move ${file_list} to ${dest_dir}" >&2
  exit "${E_BAD_MOVE}"
fi