Bash 如何在使用';set-e';在狂欢节上

Bash 如何在使用';set-e';在狂欢节上,bash,interrupt-handling,Bash,Interrupt Handling,我有一个简单的脚本: #!/bin/bash set -e trap "echo BOO!" ERR function func(){ ls /root/ } func 如果我的脚本失败,我想捕获ERR(因为在这里b/c我没有查看/root的权限)。但是,当使用set-e时,它不会被捕获。如果没有set-eERR被捕获 根据bash手册页,对于set-e: 。。。如果设置了ERR,则在shell退出之前执行trap on ERR 为什么我的陷阱没有被执行?从手册页上看,它似乎应该

我有一个简单的脚本:

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

function func(){
    ls /root/
}

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

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

。。。如果设置了ERR,则在shell退出之前执行trap on ERR


为什么我的陷阱没有被执行?从手册页上看,它似乎应该这样做。

错误
替换为
退出
,它就会工作

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

有关更多信息,请阅读是最好的解决方案:如果希望
set-e
(与:
set-o errexit
相同)与
ERR
陷阱相结合,也可以使用
set-o errtrace
(与:
set-e
相同)

简而言之:使用
set-eE
代替
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 
一个更复杂的示例
trap
以红色打印消息并同时打印退出代码的示例:
trap'printf”\e[310m%s:%s\e[m\n“BOO!”$?“ERR


manbash
谈到
set-o errtrace
/
set-E

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

我认为正在发生的事情:

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

  • 使用
    -e
    (但不使用
    -e
    ):函数内部的
    ls
    命令失败,并且由于
    set-e
    有效,Bash立即直接从函数作用域退出,并且由于没有有效的
    ERR
    陷阱(因为它不是从父作用域继承的),您的陷阱未被调用


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

你需要使用
set-o errtrace
函数来继承陷阱。

虽然这是一种可行的解决方法(尽管不需要,如果使用了
set-o errtrace
),您应该提到,如果成功终止,也会调用
EXIT
,因此您需要添加一个条件,例如
if[[$?-ne 0]]…
到处理程序。顺便说一句:最好是单引号引用陷阱处理程序,除非您明确希望它中的变量引用提前展开。如果您使用
shopt-s extdebug
,则不必这样做。谢谢,我会这样做。当我运行
bash try.sh
时,也不用使用
ls/root/
,因为它有
#!/bin/bash exit 1
>,它不会被
陷阱捕获
,如果被调用的脚本退出,有没有办法捕获它?@alper当脚本退出时,无论出于何种原因,无论是否成功,都会调用一个单独的
退出
陷阱。要仅对非零退出代码执行操作,必须选中
$?
;例如:
陷阱'ec=$?;((ec!=0))&&echo“因故障退出:$ec”'退出