Bash で 'set -e' を使用するときに ERR をトラップする方法 質問する

Bash で 'set -e' を使用するときに ERR をトラップする方法 質問する

簡単なスクリプトがあります:

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

function func(){
    ls /root/
}

func

スクリプトが失敗した場合に ERR をトラップしたいと思います (/root を調べる権限がないため、ここでは失敗します)。ただし、使用している場合はset -eトラップされません。使用しない場合はset -eERR がトラップされます。

bash のマニュアルページによるとset -e

... ERR のトラップが設定されている場合は、シェルが終了する前に実行されます。...

なぜトラップが実行されないのですか? man ページによると、実行されるはずです。

ベストアンサー1

チェプナーの答え最善の解決策です: あなたが望むならset -e(同じset -o errexit:)をトラップと組み合わせるにはERRset -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 bashset -o errtrace/について言うset -E:

設定されている場合、ERR のすべてのトラップは、シェル関数、コマンド置換、およびサブシェル環境で実行されるコマンドによって継承されます。通常、このような場合には ERR トラップは継承されません。

私が信じていることは次のとおりです。

  • それなし -e:lsコマンドは関数内で失敗し、関数内の最後のコマンドであるため、関数はls呼び出し元、つまりスクリプトの最上位スコープに の非ゼロ終了コードを報告します。その範囲ERRトラップは有効になり、呼び出されます (ただし、exitトラップから明示的に呼び出さない限り、実行は続行されることに注意してください)。

  • -e(ただし、 なし-E):lsコマンドは失敗する関数内で、そしてset -eが有効であるため、Bash即座に出口、関数スコープから直接- そしてERR罠は効いていないのでそこには(親スコープから継承されていないため)、トラップは呼び出されません。

ページは間違ってはいませんがman、この動作は必ずしも明白ではなく、推測する必要があることに同意します。

おすすめ記事