読者です 読者をやめる 読者になる 読者になる

harry’s memorandum

おれおれメモ

Bashの擬似シグナルを使ったデバッグ方法

少し前にオライリーの入門Bashを読んで、このデバッグ方法を知って「おおー」と感動をしたので、この喜びを書いてみました。


sh系には trap というコマンドでシグナルトラップができて便利ですが、bash にはさらに便利な疑似シグナルというものがあったりします。bashのmanpagerをみると、trapのsigspecをERRとした場合、コマンドが0以外でexitした場合にトラップしてくれるようです。

If a sigspec is ERR, the command arg is executed whenever a simple command has a non-zero exit status, subject to the following conditions.
The ERR trap is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test
in an if statement, part of a command executed in a && or ?? list, or if the command's return value is being inverted via !.
These are the same conditions obeyed by the errexit option.


以下は疑似シグナルERRを使ったサンプルコードです。

#!/bin/bash
errtrap()
{
  errcode=$?
  echo "error line $1: command exited with status $errcode."
}

trap 'errtrap $LINENO' ERR

failure() { return 1; }
success() { echo "success: bash function .."; return 0; }

while true; do
  sleep 1
  if [ $(($RANDOM%2)) -eq 1 ]; then
    failure
  else
    success
  fi
  sl > /dev/null 2>&1 #external command
done


実行して、見事にシェル関数のエラーと外部コマンドのエラーのときにトラップできています。$LINENOという変数でエラー時の行番号をだしているところもいい感じです。

$ bash test.sh
success: bash function ..
error line 21: command exited with status 127.
success: bash function ..
error line 21: command exited with status 127.
error line 11: command exited with status 1.
error line 21: command exited with status 127.
success: bash function ..
error line 21: command exited with status 127.
error line 11: command exited with status 1.
error line 21: command exited with status 127.
^C


疑似シグナルはERRだけでなく色々あったりします。

疑似シグナル タイミング
EXIT シェルがスクリプトを終了した
ERR コマンド、シェル関数から0ではない終了ステータスが返された
DEBUG シェルが文を実行した
RETURN source または . で実行されたシェル関数/スクリプトが終了した


便利で結構気に入っているTIPSでした。*1

入門bash 第3版

入門bash 第3版

*1:でも仕事ではBourne Shellで書くから使う機会が少ないのが悲しい