26670
シェルスクリプトで、何が起ころうが基本的にスクリプトが終了する直前に実行してほしいコマンドがあるとします。今の具体的な想定としては、 mktemp
で作ったディレクトリの削除です。

シェルスクリプトは、通常であれば上から順番にコマンドを実行していき、最後に終了しますが、ぱっと思いつくかぎりでも、以下のケースで (スクリプトの途中で)
終了します。

  * exit コマンドの実行
  * sigint, sigterm などのシグナルの受信

これらの場合でも、適切に終了処理を実行してくれるシェルスクリプトは記述できますか？
CC BY-SA 3.0
2016-06-12T05:46:48.923
26667
2016-06-12T08:43:13.327
754
question
bash shellscript
シェルスクリプトで、 ruby でいう ensure がやりたい
[trap](http://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-
Builtins.html#index-trap) で `EXIT` のハンドラを書けばよいと思います。次のようなスクリプトでテストしてみてください。

```

    #!/bin/bash
    TMPDIR=$(mktemp -d)
    trap "rm -rf $TMPDIR" EXIT
    echo "Created $TMPDIR"
    read a
    
```

実行すると `Created /tmp/tmp.d3EITJailU` のようにテンポラリディレクトリを表示して入力待ちになります。 `ENTER`
を押して正常終了したり `Ctrl`+`C` で止めたりするとそのディレクトリは消されます。
CC BY-SA 3.0
2016-06-12T06:03:46.737
26670
2016-06-12T06:03:46.737
9873
26667
answer
> sigint, sigterm などのシグナルの受信

実際の所、`SIGKILL` だけは `trap` による対応ができません。

```

    #!/bin/bash
    trap 'echo Exit' EXIT
    kill -HUP $$
    
```

`SIGHUP` の場合は、

```

    $ ./trap.sh
    Exit
    Hangup
    
```

となりますが、`kill -KILL $$` にすると以下の様になります。

```

    $ ./trap.sh
    Killed
    
```

まぁ、`SIGKILL` は特別扱いで構わないのかもしれませんが、`SIGKILL` が発行された場合でもアクションを行いたい場合もあるかもしれません。

Linux 系 OS には inotify というファイルシステムに発生するイベント(`open(2), close(2)`,
etc.)をフックする機構があります。シェルスクリプトが実行されて、何らかの原因(正常終了を含む)でシェルプロセスが終了する際にはそのスクリプトファイルをクローズします。そのクローズイベントを拾ってアクションを実行します。

```

    #!/bin/bash
    temp=$(mktemp)
    nohup sh -c "inotifywait -qq -e close \"$0\" && rm -f $temp" &>/dev/null &
    echo "Created $temp"
    read a
    
    $ ./notify.sh
    Created /tmp/tmp.JfL9ZTrmv3
    
    # 別の端末で以下を実行
    $ pkill -KILL notify.sh
    
    # notify.sh を実行した端末
    $ ./notify.sh
    Created /tmp/tmp.JfL9ZTrmv3
    Killed
    
    $ ls /tmp/tmp.JfL9ZTrmv3
    ls: cannot access '/tmp/tmp.JfL9ZTrmv3': No such file or directory
    
```

もっとも、`inotifywait` を別プロセスで起動するので、そちらに `SIGKILL` を発行されてしまうとどうにもなりませんが。
CC BY-SA 3.0
2016-06-12T08:43:13.327
26676
2016-06-12T08:43:13.327
26667
answer