在 Bash 中使用“set -e”时如何捕获 ERR

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35800082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:20:26  来源:igfitidea点击:

How to trap ERR when using 'set -e' in Bash

bashinterrupt-handling

提问by irritable_phd_syndrom

I have a simple script :

我有一个简单的脚本:

#!/bin/bash
set -e
trap "echo BOO!" ERR 

function func(){
    ls /root/
}

func

I would like to trap ERR if my script fails (as it will here b/c I do not have the permissions to look into /root). However, when using set -eit is not trapped. Without set -eERR is trapped.

如果我的脚本失败,我想捕获 ERR(因为它在这里 b/c 我没有查看 /root 的权限)。但是,使用set -e时不会被困。没有set -eERR 被困。

According to the bash man page, for set -e:

根据 bash 手册页,对于set -e

... A trap on ERR, if set, is executed before the shell exits. ...

... ERR 上的陷阱(如果设置)在 shell 退出之前执行。...

Why isn't my trap executed? From the man page it seems like it should.

为什么我的陷阱没有被执行?从手册页看来应该如此。

回答by mklement0

chepner's answeris the best solution: If you want to combine set -e(same as: set -o errexit) with an ERRtrap, also use set -o errtrace(same as: set -E).

chepner 的答案是最好的解决方案:如果您想set -e(same as: set -o errexit) 与ERR陷阱结合使用,也可以使用set -o errtrace(same as: set -E)

In short: use set -eEin lieu of just set -e:

简而言之:set -eE代替 just 使用set -e

#!/bin/bash

set -eE  # same as: `set -o errexit -o errtrace`
trap 'echo BOO!' ERR 

function func(){
  ls /root/
}

# Thanks to -E / -o errtrace, this still triggers the trap, 
# even though the failure occurs *inside the function*.
func 


man bashsays about set -o errtrace/ set -E:

man bashset -o errtrace/ set -E

If set, any trap on ERR is inherited by shell functions, command substitutions, and commands executed in a subshell environment. The ERR trap is normally not inherited in such cases.

如果设置,则 ERR 上的任何陷阱都由 shell 函数、命令替换和在子 shell 环境中执行的命令继承。在这种情况下,ERR 陷阱通常不会被继承。

What I believe is happening:

我相信正在发生的事情:

  • Without-e: The lscommand fails inside your function, and, due to being the last command in the function, the function reports ls's nonzero exit code to the caller, your top-level script scope. In that scope, the ERRtrap is in effect, and it is invoked (but note that execution will continue, unless you explicitly call exitfrom the trap).

  • With-e(but without -E): The lscommand fails inside your function, and because set -eis in effect, Bash instantlyexits, directly from the function scope- and since there is no ERRtrap in effect there(because it wasn't inherited from the parent scope), your trap is not called.

  • 没有-e:该ls命令在您的函数内失败,并且由于是函数中的最后一个命令,该函数会将ls的非零退出代码报告给调用者,即您的顶级脚本范围。在该范围内ERR陷阱生效并被调用(但请注意,执行将继续,除非您exit从陷阱中明确调用)。

  • 随着-e(但没有-E):该ls命令失败你的函数里面,因为set -e在实际上,猛砸立即退出,直接从功能范围-而因为没有ERR有效的陷阱存在(因为它没有从父作用域继承) ,你的陷阱没有被调用。

While the manpage is not incorrect, I agree that this behavior is not exactly obvious - you have to infer it.

虽然man页面没有错误,但我同意这种行为并不完全明显 - 您必须推断它。

回答by chepner

You need to use set -o errtracefor the function to inherit the trap.

您需要使用set -o errtracefor 函数来继承陷阱。

回答by Ritesh

Replace ERRwith EXITand it will work.

替换ERREXIT,它将起作用。

The syntax of the trapcommand is: trap [COMMANDS] [SIGNALS]

trap命令的语法是:trap [COMMANDS] [SIGNALS]

For more info, please read http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html

有关更多信息,请阅读http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html