Linux

inotifywaitでファイル監視するときに注意すべきこと

はじめに

inotify-toolsに含まれるinotifywaitは、指定したファイルやディレクトリに関するイベント、例えばアクセスした、修正した、削除したなどを取得できるコマンドだ。
これを使えば、例えばソースコードを修正するたびに自動でコンパイルを走らせることも出来てとても便利に使える。

参考:inotify-toolsでファイルやディレクトリを監視する - Qiita

のはずなのだが、残念ながら当初手元の環境ではうまく動かず期待する挙動を確認できなかった。
試行錯誤したところ、ようやく原因を見つけることが出来たのでメモを残しておく。

想定外の事態

やりたいことはa.txtを編集するたびにそのイベントを取得したい。
素直に書くと以下のようになる。

$ inotifywait -m -e modify a.txt

簡単に説明すると-e modifyはinotifywaitで検知できるイベントのうち編集したときのイベントのみ取得するオプションで-mはイベントを一回だけでなく継続して取得することを意味している。

期待する動作としてa.txtを編集すると以下のように表示して欲しい。

$ inotifywait -m  -e modify texdir/abstract.tex                        
Setting up watches.
Watches established.
# ここでa.txtを編集
a.txt MODIFY 

残念ながら手元の環境では期待する表示は得られなかった。

$ inotifywait -m -e modify texdir/abstract.tex                        
Setting up watches.
Watches established.
# ここでa.txtを編集
# が、無反応

原因

この問題は監視対象のファイルがいつのまにか削除されていることが原因だ。
削除されているので、それ以後のイベントは発生せず当然ながら何のイベントも取得できない。

混乱するのはa.txtは編集前も、後も目に見えて存在する点だ。
実は編集前と編集後のファイルは同じファイルに見えて、実は違うファイルになっている。

以下のようにiノードが変わっている。

$ ls -i a.txt
6032949 a.txt
# ここでa.txtを編集
$ ls -i a.txt
6033053 a.txt

inotifywaitで全てのイベントを見ても確認できる。

inotifywait -m a.txt
Setting up watches.
Watches established.
a.txt ATTRIB 
a.txt DELETE_SELF # a.txtが削除された、これ以後は何のイベントも取得できない

この挙動は使うエディターに依存する。
texのIDEであるtexstudioでは上記のような挙動だが、他のエディタ、emacsやvscode、nanoではiノードは変わらないままだった。
もちろん、後者のエディタを使った場合inotifywaitは-e modifyイベントを取得し続けることが出来る。

エディタを変えずに監視したい

使うエディタを変えるというのも一つの手だが、今回はエディタを変えない方法を考える。
原因がわかれば対処方法も分かる。
iノードを変更するエディタの場合modifyイベントを通知してくれないので-e attribで代用する。
またオプションの継続監視は出来ないので、代わりにwhileループで監視する。
以下のように、iノードを変更するエディタでも変更しないエディタでも編集を検知することが出来ている。

$ while; do
# 2> /dev/null はinotifyを起動するたびに表示されるメッセージを非表示にするため
echo `inotifywait -e modify -e attrib a.txt 2> /dev/null` 
done
# a.txtをtexstudioで編集
a.txt ATTRIB
# a.txtをemacsで編集
a.txt MODIFY

参考

linux - inotify delete_self when modifying and saving a file - Stack Overflow