web-dev-qa-db-ja.com

トラップコマンドを使用してエラーをトリガーする方法

Ubuntu 12.04.2を使用しています。 「trap」コマンドを使用してシェルスクリプトの異常またはエラーをキャプチャしようとしていますが、「Error」出口を手動でトリガーしようとしています。

出口1を試しましたが、「エラー」信号をトリガーしません。

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

「エラー」終了信号を手動でトリガーする方法がわからない場合は、

13
forestclown

ERRトラップは、シェル自体がゼロ以外のエラーコードで終了したときにコードを実行するのではなく、条件の一部ではないそのシェルによって実行されたコマンド(_if cmd..._、または_cmd || ..._...のように)ゼロ以外の終了ステータスで終了します(_set -e_が終了する原因と同じ条件)シェル)。

ゼロ以外の終了ステータスでシェルの終了時にコードを実行する場合は、代わりにEXITにトラップを追加し、そこで_$?_を確認する必要があります。

_trap '[ "$?" -eq 0 ] || echo hi' EXIT
_

ただし、トラップされたシグナルでは、シグナルトラップとEXITトラップの両方が実行されるため、次のように実行することもできます。

_unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
  ret=$?
  if [ -n "$killed_by" ]; then
    echo >&2 "Ouch! Killed by $killed_by"
    exit 1
  Elif [ "$ret" -ne 0 ]; then
    echo >&2 "Died with error code $ret"
  fi' EXIT
_

または、シグナルで$((signum + 128))のような終了ステータスを使用するには:

_for sig in INT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT
_

ただし、親プロセスがbashのようなシェルであり、SIGINTまたはSIGQUITで正常に終了すると、 waitおよびcooperative exit 端末割り込みの処理。そのため、実際に中断されたことを親に報告し、SIGINT/SIGQUITを受け取った場合は自分自身を終了することを検討するように、代わりに同じシグナルで自分を殺すことを確認することをお勧めします。

_unset killed_by
for sig in INT QUIT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
  if [ -n "$killed_by" ]; then
    trap - "$killed_by" # reset handler
    # ulimit -c 0 # possibly disable core dumps
    kill -s "$killed_by" "$$"
  else
    exec "$ret"
  fi' EXIT
_

ERRトラップを発生させたい場合は、falsetestなどのゼロ以外の終了ステータスでコマンドを実行してください。

20

関数の終了時にステータスを設定するには、exitではなくreturnを使用します(関数がreturnなしでフォールスルーした場合、ステータスは最後に実行されたステートメントのステータスになります。)質問の例でreturnexitに置き換えると、意図したとおりに動作します。トラップはERR疑似信号でトリガーされ、「hi」が出力されます。追加の考慮事項については、これを試してください:

#!/bin/bash

func()
{
    echo 'in func'
    return 99
    echo 'still in func'
}

trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'

0を返す、ERRトラップをコメント化する、ERRハンドラー内でEXITトラップを取り消さない、ERRハンドラーを終了しない、戻り値を削除してfuncの最後のステートメントとしてfalseを配置するなど、さまざまな変更を試すことができます。

6
sdenham