繁体   English   中英

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

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

我有一个简单的脚本:

#!/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 退出之前执行。 ...

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

chepner 的答案是最好的解决方案:如果要将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[31m%s: %s\\e[m\\n" "BOO!" $?' ERR


man bash关于set -o errtrace / set -E

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

我相信正在发生的事情:

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

  • 随着-e (但没有-E )的ls命令自己的函数中失败,因为set -e生效,猛砸立即退出,直接从功能范围-而因为没有ERR陷阱效应存在(因为它不是从父作用域继承的),则不会调用您的陷阱。

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

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

EXIT替换ERR它将起作用。

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

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

我们有这些调试选项:

  • -e失败立即退出
  • -E如果设置,ERR 上的任何陷阱都由 shell 函数继承
  • -u存在未绑定变量时退出
  • -o给出要设置的选项名称
    • pipefail 最后(最右边)命令的返回值(退出代码)
  • -v在读取时打印所有 shell 输入行
  • -x打印命令跟踪

为了处理错误,我们可以使用trap捕获目录

trap 'echo >&2 "Error - exited with status $? at line $LINENO' ERR

或者更好的版本ref

trap 'echo >&2 "Error - exited with status $? at line $LINENO:";
         pr -tn $0 | tail -n+$((LINENO - 3)) | head -n7' ERR

或 function:

function __error_handing__(){
    local last_status_code=$1;
    local error_line_number=$2;
    echo 1>&2 "Error - exited with status $last_status_code at line $error_line_number";
    perl -slne 'if($.+5 >= $ln && $.-4 <= $ln){ $_="$. $_"; s/$ln/">" x length($ln)/eg; s/^\D+.*?$/\e[1;31m$&\e[0m/g;  print}' -- -ln=$error_line_number $0
}

并这样称呼它:

trap  '__error_handing__ $? $LINENO' ERR

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM