一种 bash script 进行错误处理的思路备忘

在 bash 脚本中使用 `set -e` 是很常见的操作了,这个命令按照 POSIX 标准有下面的作用:
-e    When this option is on, when any command fails (for any of
      the reasons listed in Section 2.8.1, Consequences of Shell
      Errors or by returning an exit status greater than zero),
      the shell immediately shall exit, as if by executing the
      exit special built-in utility with no arguments, with the
      following exceptions:

       1. The failure of any individual command in a multi-
          command pipeline shall not cause the shell to exit.
          Only the failure of the pipeline itself shall be
          considered.

       2. The -e setting shall be ignored when executing the
          compound list following the while, until, if, or elif
          reserved word, a pipeline beginning with the !
          reserved word, or any command of an AND-OR list other
          than the last.

       3. If the exit status of a compound command other than a
          subshell command was the result of a failure while -e
          was being ignored, then -e shall not apply to this
          command.

      This requirement applies to the shell environment and each
      subshell environment separately. For example, in:

          set -e; (false; echo one) | cat; echo two

      the false command causes the subshell to exit without
      executing echo one; however, echo two is executed because
      the exit status of the pipeline (false; echo one) | cat is
      zero.
但是在脚本中如此操作会使整个脚本都被 `set -e` 覆盖,而且无法以 `try...catch` 的思路后处理错误。 如何提高灵活度,只对需要的函数处理,同时提供错误处理能力呢? ## 解决方案
$ set -e
$ function a(){ if [ $b -eq 1 ]; then somethingwrong; else return 0; fi; }

$ b=2  # 执行无错误的分支
$ ! a  # 一切正常
$ a    # 一切正常

$ b=1  # 执行有错误的分支
$ ! a && echo $? # handle 错误
-bash: somethingwrong: command not found
0
$ ! a  # ignore 错误
$ a  # 不要 catch 错误
这看起来就像魔法一样,而且看起来是如此直观,仿佛某个新语言的语法糖一般,对吧? 只需要在设置 `set -e` 后,对于需要忽略错误的函数前面加一个 `!`, 对需要处理错误的函数前面加 `!`,后面使用 `&&` 接错误处理命令, 需要打断脚本运行的错误,就不要管他。 这样的处理对现有脚本的侵入性也非常的小,只需要关注可能有问题的函数即可。 ## 原理 那么这是如何实现的呢,这看起来很甜的解决方案并不是 bash 的语法糖,而是一个特性, 详细阅读 POSIX 原文的话可能会发现,POSIX 的要求为比较拗口的 `The -e setting shall be ignored when ... a pipeline beginning with the !`,但 bash 在实践中将其表述为了更加拟人的规则:
The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !.
因此我们可以通过一个简单的 `!` 来阻止 `-e` 开关停止脚本,然后对将非 0 返回结果反转后的 0(True) 使用 && 来处理。

评论

发表评论

此博客中的热门博文

clash for windows 系统代理时 pip 出现 ProxyError 的情况分析记录

在 VPS 上使用 Cloudflare Warp 提升媒体解锁能力 & 路由解决办法

ESXi 配置 DSM 黑群晖踩坑记