私は簡単なスクリプトを持っています:
#!/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のトラップは、設定されている場合、シェルが終了する前に実行されます。 ...
トラップが実行されないのはなぜですか?マニュアルページからは、そうすべきだと思われます。
chepner's answer が最適なソリューションです:必要に応じてset -e
( :ERR
トラップのあるset -o errexit
)、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
man bash
はset -o errtrace
/set -E
について述べています:
設定すると、ERRのトラップはシェル関数、コマンド置換、およびサブシェル環境で実行されるコマンドに継承されます。このような場合、ERRトラップは通常継承されません。
私が信じていることは起こっている:
Without-e
:ls
コマンドは関数内で失敗し、関数の最後のコマンドであるため、関数はls
のゼロ以外の終了コードを呼び出し元であるトップレベルスクリプトスコープに報告します。 そのスコープでは、ERR
トラップが有効であり、呼び出されます(ただし、トラップからexit
を明示的に呼び出さない限り、実行は継続することに注意してください)。
あり-e
(ただし-E
なし):ls
コマンドは失敗します関数内、およびset -e
が有効であるため、Bash 即座にが終了します- 関数スコープから直接-そして、有効なERR
トラップがないためthere(親スコープから継承されていないため)、トラップは呼び出されません。
man
ページは間違っていませんが、この動作は明確ではないことに同意します。推測する必要があります。
関数がトラップを継承するには、set -o errtrace
を使用する必要があります。
ERR
をEXIT
に置き換えると、動作します。
trap
コマンドの構文は次のとおりです。trap [COMMANDS] [SIGNALS]
詳細については、 http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html をご覧ください。