スクリプトの実行が成功しても失敗しても、スクリプトをスムーズに終了させることができます。
シェルスクリプトの開始を検出するのは難しくありませんが、シェルスクリプトの終了を検出するのはそれほど簡単ではありません。スクリプトが期待どおりに正常に終了するか、予期しないエラーで失敗するかを確かめる方法がないからです。スクリプトが失敗した場合、処理中の内容を記録しておくと便利ですが、それが不便な場合もあります。 trapコマンドは、スクリプトの終了シグナルをキャッチし、事前に定義された方法で応答することで、この問題を解決するために存在します。
レスポンス失敗
エラーが1つでも発生すると、エラーの連鎖につながる可能性があります。以下のスクリプト例では、最初に/tmpにテンポラリディレクトリを作成し、別の圧縮形式でパックする前に、テンポラリディレクトリでアンパックやファイル処理などの操作を実行できるようにしています:
#!/usr/bin/env bashCWD=`pwd`TMP=${TMP:-/tmp/tmpdir}## create tmp dirmkdir "${TMP}"## extract files to tmptar xf "${1}" --directory "${TMP}"## move to tmpdir and run commandspushd "${TMP}"for IMG in *.jpg; domogrify -verbose -flip -flop "${IMG}"tar --create --file "${1%.*}".tar *.jpg## move back to origin## bundle with bzip2bzip2 --compress "${TMP}"/"${1%.*}".tar \--stdout > "${1%.*}".tbz## clean up/usr/bin/rm -r /tmp/tmpdir
通常、スクリプトは期待通りに実行されます。しかし、アーカイブ内のファイルが期待されるJPEGではなくPNGである場合、スクリプトは途中で失敗し、別の問題が発生します: 一時ディレクトリを削除する最後のステップが正しく実行されないのです。テンポラリディレクトリを手動で削除する場合は問題ありませんが、テンポラリディレクトリを手動で削除しない場合、このスクリプトの次の実行時に、予測できない残ファイルだらけの既存のテンポラリディレクトリを処理しなければなりません。
一つの解決策は、スクリプトの最初に予防的削除ロジックを追加して、この状況に対処することです。しかし、このやり方は少々乱暴で、この問題は構造的に解決すべきです。トラップを使うのはエレガントなアプローチです。
トラップによる信号の捕捉
プログラムの実行中にシグナルを捕捉するトラップができます。killコマンドやkillallコマンドを使ったことがある人は、すでにSIGTERMというシグナルを使っています。これに加えて、trap -lまたはtrap --listを実行すると、さらに多くのシグナルをリストアップできます:
$ trap --list1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR111) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+338) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1253) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-758) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-263) SIGRTMAX-1 64) SIGRTMAX
トラップが認識できるシグナルは上記以外にもあります:
EXIT: プロセス終了時にプロセスから通知されます。- ERR: プロセスがゼロ以外のステータスコードで終了したときに発せられるシグナル
DEBUGデバッグモードを示すブール値
Bashでシグナル・トラッピングを実装したい場合は、トラップ後に実行するコマンドと、トラップするシグナルのリストを追加するだけです。
たとえば、次の行は、プロセスの実行中にユーザーが Ctrl + C キーの組み合わせを押したときに発せられる SIGINT シグナルをキャプチャします:
trap "{ echo 'Terminated with Ctrl+C'; }" SIGINT
したがって、SIGINT、SIGTERM、Process Error Exit、Process Normal Exitなどのシグナルを捕捉するtrapを使用し、一時ディレクトリを正しく処理することで、上記のスクリプトの欠陥を修正することができます:
#!/usr/bin/env bashCWD=`pwd`TMP=${TMP:-/tmp/tmpdir}"{ /usr/bin/rm -r "${TMP}" ; exit 255; }" \SIGINT SIGTERM ERR EXIT## create tmp dirmkdir "${TMP}"tar xf "${1}" --directory "${TMP}"## move to tmp and run commandspushd "${TMP}"for IMG in *.jpg; domogrify -verbose -flip -flop "${IMG}"tar --create --file "${1%.*}".tar *.jpg## move back to origin## zip tarbzip2 --compress $TMP/"${1%.*}".tar \--stdout > "${1%.*}".tbz
より複雑な関数については、 使用してトラップ文を簡略化することもできます。
Bashでの信号キャプチャ
シグナルキャプチャは、スクリプトがすべてのタスクを正常に実行したかどうかにかかわらず、正しくクリーンアップを行うことを可能にし、スクリプトの信頼性を高めることができます。あなたのスクリプトにシグナルキャプチャを追加してみてください。





