08 September 2019

(Ubuntu 18.04) inotifywaitでファイル更新を監視しコマンド実行する

inotifywaitを使うと、「指定したファイル」や「指定したディレクトリ内のファイル」に対する読み書きアクセスを検知することができる。

まず簡単な例として、ディレクトリ内のファイルへのアクセスを監視し続け、標準出力に結果を吐き出させる例を作成。

なお、 -m オプションをつけて、Ctrl + C を押すまで監視し続けてみる

$ inotifywait -m --exclude '.Trash'  /home/vm/Desktop/src/
Setting up watches.
Watches established.
/home/vm/Desktop/src/ OPEN,ISDIR 
/home/vm/Desktop/src/ ACCESS,ISDIR 
/home/vm/Desktop/src/ ACCESS,ISDIR 
/home/vm/Desktop/src/ CLOSE_NOWRITE,CLOSE,ISDIR 
/home/vm/Desktop/src/ OPEN test01.txt
/home/vm/Desktop/src/ OPEN,ISDIR 
/home/vm/Desktop/src/ ACCESS,ISDIR 
/home/vm/Desktop/src/ ACCESS,ISDIR 
/home/vm/Desktop/src/ CLOSE_NOWRITE,CLOSE,ISDIR 
/home/vm/Desktop/src/ ACCESS test01.txt
/home/vm/Desktop/src/ CLOSE_NOWRITE,CLOSE test01.txt
/home/vm/Desktop/src/ OPEN test01.txt
/home/vm/Desktop/src/ CREATE .goutputstream-C2GT7Z
/home/vm/Desktop/src/ OPEN .goutputstream-C2GT7Z
/home/vm/Desktop/src/ ATTRIB .goutputstream-C2GT7Z
/home/vm/Desktop/src/ CLOSE_WRITE,CLOSE test01.txt
/home/vm/Desktop/src/ MODIFY .goutputstream-C2GT7Z
/home/vm/Desktop/src/ MOVED_FROM .goutputstream-C2GT7Z
/home/vm/Desktop/src/ MOVED_TO test01.txt
/home/vm/Desktop/src/ CLOSE_WRITE,CLOSE test01.txt
 〜 以下省略 (Ctrl + C で終了できる) 〜

このキャプチャ例は、nautilusでディレクトリを開き、テキストファイルをgeditで編集し保存しただけのアクションで検出されたイベントだ。 検出イベントがあまりにも多すぎる…

抽出するイベントを -e オプションで絞り込んでみる

geditでファイルを開き、保存した場合
$ inotifywait -m --exclude '.Trash' -e MODIFY -e CREATE -e MOVED_TO /home/vm/Desktop/src/
cc /home/vm/Desktop/src/ CREATE .goutputstream-TNN57Z
XX /home/vm/Desktop/src/ MODIFY .goutputstream-TNN57Z
cc /home/vm/Desktop/src/ MOVED_TO test01.txt
vimでファイルを開き、保存した場合
$ inotifywait -m --exclude '.Trash' -e MODIFY -e CREATE -e MOVED_TO /home/vm/Desktop/src/
/home/vm/Desktop/src/ CREATE .test01.txt.swp
/home/vm/Desktop/src/ CREATE .test01.txt.swx
/home/vm/Desktop/src/ CREATE .test01.txt.swp
/home/vm/Desktop/src/ MODIFY .test01.txt.swp
/home/vm/Desktop/src/ MODIFY .test01.txt.swp
/home/vm/Desktop/src/ MODIFY .test01.txt.swp
/home/vm/Desktop/src/ CREATE 4913
/home/vm/Desktop/src/ MOVED_TO test01.txt~
/home/vm/Desktop/src/ CREATE test01.txt
/home/vm/Desktop/src/ MODIFY test01.txt
/home/vm/Desktop/src/ MODIFY test01.txt
/home/vm/Desktop/src/ MODIFY .test01.txt.swp
コマンドラインのcpコマンドでファイルをコピーした場合
$ inotifywait -m --exclude '.Trash' -e MODIFY -e CREATE -e MOVED_TO /home/vm/Desktop/src/
/home/vm/Desktop/src/ CREATE test04.txt
/home/vm/Desktop/src/ MODIFY test04.txt

ファイルの保存、ファイルのコピーという一つのアクションを起こすと、複数のイベントがキャプチャされる。ある特定のイベントをキャプチャしたい場合、さらに文字列を抜き出すということをすれば…

test.sh (MODIFYイベントのみを抜き出すスクリプト)
#/bin/sh
 
inotifywait -m --exclude '.Trash' -e MODIFY -e CREATE -e MOVED_TO /home/vm/Desktop/src/ |
while read str
do
    if [ "`echo $str | grep 'MODIFY'`" ]
    then
        echo "一致 ${str}"
    else
        echo "不一致 ${str}"
    fi
done

このスクリプトを使っても、やはり、「保存」という一つのアクションに対して、一つのイベント抽出は難しい。

最終的に、inotifywait の常駐監視機能(-m)オプションを使わないことで解決

test-02.sh (スクリプト側のwhileループで常駐監視する例)
#/bin/sh
 
while :
do
    inotifywait --exclude '.Trash' -e MODIFY -e CREATE -e MOVED_TO /home/vm/Desktop/src/ > /dev/null 2>&1
 
    gdialog --title "inotifywait" --yesno '/home/vm/Desktop/src/ のファイルが変更されました\n' 0 0
 
    RESPONSE=$?
    # yes=0, no=1, esc=255
    case $RESPONSE in
        0) 
            ./user_command.sh;;
        1)   
            ;;
        255)
            ;;
    esac
done