受け取ったシグナルに合わせて、指定した処理を実行してくれるtrap
、とても便利ですよね(´・ω・`) 個人的には「作成した一時ファイルを終了後に必ず破棄する」という処理を実装する際によく利用しています。
path=$(mktemp)
trap "rm -f ${path}" EXIT
ひとつのシグナルに対する処理はそのスクリプト内において1回しか定義できない、つまりtrapを呼び出すたびにどんどん上書きされてしまうことに注意する必要があります。たとえば「複数の一時ファイルを作成し、処理終了後にそれらをすべて破棄する」とき、ついつい次のようなコードを書きがちです。
trap_test.sh
#!/bin/bash
set -x
path1=$(mktemp)
path2=$(mktemp)
path3=$(mktemp)
for path in ${path1} ${path2} ${path3}; do
trap "rm -f ${path}" EXIT
done
# === do_something ===
exit 0
これを実行した結果が以下の通りになります。trapを3回呼び出して、作成した3つの一時ファイルを処理終了後に削除することを意図していますが、rm
は一度しか呼ばれていません。また少しわかりづらいのですが、trapにより呼ばれたrm
はpath3
を削除しています。つまりtrap
は呼び出すごとに指定した処理を上書きしているとわかります。
$ bash trap_test.sh
++ mktemp
+ path1=/tmp/tmp.0dzHkNQP8n
++ mktemp
+ path2=/tmp/tmp.CtuP5ZdxyW
++ mktemp
+ path3=/tmp/tmp.8TZD5DRKKI
+ for path in '${path1}' '${path2}' '${path3}'
+ trap 'rm -f /tmp/tmp.0dzHkNQP8n' EXIT
+ for path in '${path1}' '${path2}' '${path3}'
+ trap 'rm -f /tmp/tmp.CtuP5ZdxyW' EXIT
+ for path in '${path1}' '${path2}' '${path3}'
+ trap 'rm -f /tmp/tmp.8TZD5DRKKI' EXIT
+ exit 0
+ rm -f /tmp/tmp.8TZD5DRKKI
したがって意図通りにするためには、trap_test.sh
を次のように修正する必要があります。
trap_test.sh
#!/bin/bash
set -x
path1=$(mktemp)
path2=$(mktemp)
path3=$(mktemp)
trap "rm -f ${path1} ${path2} ${path3}" EXIT
# === do_something ===
exit 0
この実行結果は以下の通りです。作成した3つの一時ファイルがrm
の対象になっていることが確認できます(´・ω・`)
$ bash trap_test.sh
++ mktemp
+ path1=/tmp/tmp.vrVWvDvk9P
++ mktemp
+ path2=/tmp/tmp.i2aLRF3WMr
++ mktemp
+ path3=/tmp/tmp.Y6LOH2QYnw
+ trap 'rm -f /tmp/tmp.vrVWvDvk9P /tmp/tmp.i2aLRF3WMr /tmp/tmp.Y6LOH2QYnw' EXIT
+ exit 0
+ rm -f /tmp/tmp.vrVWvDvk9P /tmp/tmp.i2aLRF3WMr /tmp/tmp.Y6LOH2QYnw