Edited at

[Linux] inotifywaitを使ってファイル更新時に任意のコマンドを実行する

More than 3 years have passed since last update.

[2016/07/29 追記]

systemd.pathを使えば同じことができそうなことが判明・・・orz

[2016/07/29 さらに追記]

systemd.pathからUnitにファイルパスを渡す方法が不明。できないのかな。

できないのならこのスクリプトも意味があるけど。

どなたかご存知でしたら教えてください。


事前準備

inotify-toolsをインストール (Redhat系)

yum install -y inotify-tools


ソース


watch-file.sh

#!/bin/bash -eu

trap "exit 0" 3 # QUITシグナルで停止

WATCH_DIR=$1 # 監視するディレクトリ
FILE_PATTERN=$2 # ファイル名正規表現
COMMAND=$3 # ファイル更新時に実行するコマンド

# --formatで"ディレクトリ ファイル名 イベント"の形式で出力するように指定
inotifywait -e CLOSE_WRITE -m -r ${WATCH_DIR} --format "%w %f %e" | \
while read LINE; do

# --format指定した通りに変数に格納
declare -a eventData=(${LINE})
dirPath=${eventData[0]}
fileName=${eventData[1]}

# ファイル名パターンマッチング (マッチしなかったら無視)
[[ $fileName =~ ${FILE_PATTERN} ]] || continue

${COMMAND} "${dirPath}${fileName}"

done



解説


  • オプション-mをつけないと最初のイベントで終了する。

  • オプション-rでディレクトリを再帰的に監視

  • 後で受け取りやすいように--formatオプション指定

  • bashの正規表現マッチングでファイル名の判定


使い方

watch-file.sh /data/app '^application-data-.*\.csv$' "echo" 

フォアグラウンドで実行し続けるので Ctrl+C で止める。


Redhat系OSのサービス化

inotifywaitはフォアグラウンドで継続実行されるのでsystemdサービスにする。


/usr/lib/systemd/system/watch-file.service

[Unit]

Description=Watch files and archive

[Service]
Type=simple
ExecStart=/path/to/watch-file.sh /data/app '^.*\.csv$' gzip
ExecStop=/usr/bin/kill -QUIT $MAINPID
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target


systemctl enable watch-file

systemctl start watch-file

これでZABBIXとかでサービス監視もできるようになる。