BLOGTIMES
2015/08/13

bash の trap に複数のコマンドを登録したい

  sh  cli 
このエントリーをはてなブックマークに追加

bash を使うときにスクリプトの後処理を trap に仕込んでおくと便利です

ただ、これには弱点があって、trap を複数回呼出してしまうとコマンドが上書きされてしまい、最後にセットしたコマンドしか実行されないということに気づきました。仕様的にはシンプルで合理的なんでしょうが、複数のファイルにまたがるようなシェルスクリプトのような場合、trap を書く位置が問題になります。例えば以下のようなスクリプトを書くと、/path/to/tmp2 のファイルは実行が終わると削除されますが、/path/to/tmp1 のファイルは削除されずに残ってしまって不便なのです。

touch /path/to/tmp1 trap 'rm -f "/path/to/tmp1"' EXIT touch /path/to/tmp2 trap 'rm -f "/path/to/tmp2"' EXIT

trap だけをまとめて書けばいいのかもしれませんが、いろいろと場合分けがある場合もありますし、一時ファイルを生成する処理を書いたときに、後片付けのための処理も対で書いておく方がプログラム的な見通しも良くなります。今回はなんとかして逐次的に trap に処理を追加できる方法が実現できないか試してみることにします。jQuery の ready()*1 への function の登録に近いものをイメージしながら実装しました。

できるだけシンプルな実装で

trap は trap -p (シグナル) とすることで、現在登録されている trap の内容を読み取ることができます。今回はその出力を加工して、コマンドをセミコロンでつないでいくというとても単純なものです。今回はなるべくいろいろな環境で実行できるように sed しか使わずにシンプルに実現してみました。後処理に使うということで、実行順序は登録の逆順(つまりスタックのように)で実行されるようにしてあります。シングルクォートを扱えるようにするために、ちょっと sed のルールが超絶ダサいことになっていますが、一応これで動いたのでよしとします。もっといい実装があればぜひ教えてください。

push_trap(){ trap "$1;$(echo $(trap -p $2) | sed -r "s/[^']+'(.+)'[^']+$/\1/" | sed -r 's/'\''\\'\'''\''/'\''/g' )" $2 }

通常の trap と異なりシグナルは一つしか指定できないのと、-l と -p オプションも実装していません。
これは複数のシグナルを指定できるようにすると話がややこしくなるためにわざとそのようにしました。
-l と -p が必要になったら、オリジナルのコマンドを使ってください。

実際の動作

こんな感じで必要な動作が追加できます。

$ push_trap 'echo "aaa"' EXIT $ trap -p EXIT trap -- 'echo "aaa";' EXIT $ $ push_trap "echo 'bbb'" EXIT $ trap -p EXIT trap -- 'echo '\''bbb'\'';echo "aaa";' EXIT $ $ TMP_FILE=/path/to/tmp $ push_trap "rm -f \"$TMP_FILE\"" EXIT $ trap -p EXIT trap -- 'rm -f "/path/to/tmp";echo '\''bbb'\'';echo "aaa";' EXIT $ exit bbb aaa

トラックバックについて
Trackback URL:
お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/7821
Trackbacks
このエントリにトラックバックはありません
Comments
愛のあるツッコミをお気軽にどうぞ。[policy]
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントはありません
Comments Form

コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。

OpenID を使ってログインすることができます。

Identity URL: Yahoo! JAPAN IDでログイン