簡體   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