Bash
シグナルとシステムイベントに反応するための「トラップ」の使用
サーチ…
構文
- トラップアクションsigspec ...#シグナルのリストで "アクション"を実行する
- trap sigspec ...#省略するとシグナルのトラップがリセットされます
パラメーター
パラメータ | 意味 |
---|---|
-p | 現在インストールされているトラップを一覧表示する |
-l | リスト信号名と対応する番号 |
備考
trap
ユーティリティは、特別なシェルを内蔵しています。これはPOSIXで定義されていますが、bashでは便利な拡張もいくつか追加されています。
#!/bin/sh
で始まるPOSIX互換の例と、 #!/bin/bash
で始まる例は、bash拡張を使用します。
シグナルは、シグナル番号、シグナル名(SIG接頭辞なし)、または特殊キーワードEXIT
いずれかです。
POSIXによって保証されているものは次のとおりです。
数 | 名 | ノート |
---|---|---|
0 | 出口 | 終了コードに関係なく常にシェル出口で実行する |
1 | SIGHUP | |
2 | SIGINT | これが^C 送るものです |
3 | SIGQUIT | |
6 | SIGABRT | |
9 | SIGKILL | |
14 | SIGALRM | |
15 | SIGTERM | これはデフォルトでkill 送信するものです |
SIGINTまたはCtl + Cをキャッチする
トラップはサブシェルのためにリセットされるので、 sleep
は^C
によって送られたSIGINT
シグナル(通常は終了することによって)に対しても動作しますが、親プロセス(シェルスクリプト)は実行しません。
#!/bin/sh
# Run a command on signal 2 (SIGINT, which is what ^C sends)
sigint() {
echo "Killed subshell!"
}
trap sigint INT
# Or use the no-op command for no output
#trap : INT
# This will be killed on the first ^C
echo "Sleeping..."
sleep 500
echo "Sleeping..."
sleep 500
また、 ^C
2回押してメインプログラムを終了できるようにした変種:
last=0
allow_quit() {
[ $(date +%s) -lt $(( $last + 1 )) ] && exit
echo "Press ^C twice in a row to quit"
last=$(date +%s)
}
trap allow_quit INT
はじめに:一時ファイルのクリーンアップ
trap
コマンドを使用してシグナルをtrap
することができます。これは、シェルと等価であるsignal()
又はsigaction()
信号を捕捉するためにCおよび他のほとんどのプログラミング言語で呼び出します。
trap
最も一般的な使い方の1つは、予期しない終了と予期しない終了の両方で一時ファイルをクリーンアップすることです。
残念ながら、十分なシェルスクリプトではこれを行いません:-(
#!/bin/sh
# Make a cleanup function
cleanup() {
rm --force -- "${tmp}"
}
# Trap the special "EXIT" group, which is always run when the shell exits.
trap cleanup EXIT
# Create a temporary file
tmp="$(mktemp -p /tmp tmpfileXXXXXXX)"
echo "Hello, world!" >> "${tmp}"
# No rm -f "$tmp" needed. The advantage of using EXIT is that it still works
# even if there was an error or if you used exit.
終了時に実行するトラップ作業のリストを累積します。
テンポラリファイルをクリーンアップするためのtrap
を追加することを忘れたり、終了時に他の作業をしたりしたことがありますか?
別のものをキャンセルしたトラップを1つ設定しましたか?
このコードを使用すると、コードのどこかに大きなtrap
文が1つずつあるのではなく、一度に1つの項目を終了するときに行う作業を簡単に追加できます。
# on_exit and add_on_exit
# Usage:
# add_on_exit rm -f /tmp/foo
# add_on_exit echo "I am exiting"
# tempfile=$(mktemp)
# add_on_exit rm -f "$tempfile"
# Based on http://www.linuxjournal.com/content/use-bash-trap-statement-cleanup-temporary-files
function on_exit()
{
for i in "${on_exit_items[@]}"
do
eval $i
done
}
function add_on_exit()
{
local n=${#on_exit_items[*]}
on_exit_items[$n]="$*"
if [[ $n -eq 0 ]]; then
trap on_exit EXIT
fi
}
終了時の子プロセスの強制終了
トラップ式は個々の関数またはプログラムである必要はなく、より複雑な式でもあります。
jobs -p
とkill
を組み合わせることで、終了時にシェルの子プロセスをすべて終了させることができます。
trap 'jobs -p | xargs kill' EXIT
端末のウィンドウサイズの変化に反応する
信号WINCH(WINdowCHange)があります。これは、端末ウィンドウのサイズを変更すると起動します。
declare -x rows cols
update_size(){
rows=$(tput lines) # get actual lines of term
cols=$(tput cols) # get actual columns of term
echo DEBUG terminal window has no $rows lines and is $cols characters wide
}
trap update_size WINCH