C 言語だと、atexit() という関数がありますが、bash にも似た機能があることを知りました。
bash スクリプトが Ctrl+C で途中中断される場合を想定し、スクリプトの処理途中で生成される一時ファイルを削除(ゴミ掃除)したい場合があります。そんな時には、
trap "rm ..." SIGINT という具合に書くのが定石かと思っていました。しかし、そのような書き方だと、スクリプト全体の終了時にも rm の記述をすることになります。次のような具合に・・・
#!/bin/bash
#
# Name: test_trap_SIGINT.bash
#
TEMPFILE=$(mktemp /tmp/.${0##*/}.$RANDOM$RANDOM.XXXXXX)
trap "echo trapped ; rm -f $TEMPFILE" SIGINT
echo $TEMPFILE
# 一時ファイルを使った処理を行う ...
sleep 10 # このサンプルでは、スリープ
#
rm -f $TEMPFILE
exit 0
このサンプルの実行イメージは次のようになります。
途中中断しない場合
# ./test_trap_SIGINT.bash
/tmp/.test_trap_SIGINT.bash.2085610279.7jIDoS
# ls -l /tmp/.test_trap_SIGINT.bash.2085610279.7jIDoS
ls: /tmp/.test_trap_SIGINT.bash.2085610279.7jIDoS: No such file or directory
途中で Ctrl+C した場合
# ./test_trap_SIGINT.bash
/tmp/.test_trap_SIGINT.bash.579227843.ewVGq4
trapped
# ls -l /tmp/.test_trap_SIGINT.bash.579227843.ewVGq4
ls: /tmp/.test_trap_SIGINT.bash.579227843.ewVGq4: No such file or directory
最近、このパターンでスクリプトを書いていたら、一時ファイル生成後に途中終了 (exit 1) させたい条件が複数あり、いちいち rm を記述しました。
しかしハテ?もしかして atexit(3) のような機能はないものか?
っと、help を見てみますと、、、
# help trap
trap: trap [arg] [signal_spec ...] or trap -l
The command ARG is to be read and executed when the shell receives
signal(s) SIGNAL_SPEC. If ARG is absent all specified signals are
reset to their original values. If ARG is the null string each
SIGNAL_SPEC is ignored by the shell and by the commands it invokes.
If a SIGNAL_SPEC is EXIT (0) the command ARG is executed on exit from
the shell. If a SIGNAL_SPEC is DEBUG, ARG is executed after every
command. If ARG is `-p' then the trap commands associated with
each SIGNAL_SPEC are displayed. If no arguments are supplied or if
only `-p' is given, trap prints the list of commands associated with
each signal number. Each SIGNAL_SPEC is either a signal name in
or a signal number. `trap -l' prints a list of signal names and their
corresponding numbers. Note that a signal can be sent to the shell
with "kill -signal $$".
あるではないですか・・・さすが bash ですね。
なので、次のように書けます。
#!/bin/bash
#
# Name: test_trap_EXIT.bash
#
TEMPFILE=$(mktemp /tmp/.${0##*/}.$RANDOM$RANDOM.XXXXXX)
trap "echo trapped ; rm -f $TEMPFILE" EXIT
echo $TEMPFILE
# 一時ファイルを使った処理を行う ...
sleep 10 # このサンプルでは、スリープ
#
exit 0
注意点としては、もし
trap "トラップ内容" SIGINT EXIT と書くと、Ctrl+C 中断の際にトラップ内容が2回実行されることになります。