ディレクトリツリーの変更を監視する
1. 概要
このチュートリアルでは、inotifywaitを使用してディレクトリツリーの変更を監視する方法を学習します。 たとえば、新しいファイルが作成されたときにそれを検出する方法を見ていきます。
問題の紹介から始めましょう。 次に、inotifyイベントについて学習します。 最後に、 inotifywait コマンドと、それを使用して問題を解決する方法について説明します。
2. 依存関係
この例ではinotifywaitコマンドを使用するため、インストールされていることを確認する必要があります。 インストールされていない場合は、inotify-toolsパッケージをインストールして追加できます。 Debianディストリビューションなどがある場合は、rootとしてapt-getコマンドを実行してパッケージをインストールできます。
$ apt-get install inotify-tools
一方、Red Hatディストリビューションなどがある場合は、 yum コマンドを使用できますが、最初にepel-releaseリポジトリをインストールする必要があります。
$ yum install epel-release
$ yum install inotify-tools
3. 問題の紹介
main というディレクトリから始めましょう。このディレクトリには、いくつかのサブディレクトリが含まれています。 tree コマンドを使用すると、mainディレクトリツリーを確認できます。
$ tree main/
main/
├── 1
│ ├── 1
│ └── 2
│ └── 1
├── 2
└── 3
├── 1
└── 2
└── 1
└── 1
10 directories, 0 files
最初に、このディレクトリツリーを監視します。たとえば、ファイルがいつ作成または削除されたか、開かれたか、書き込まれたか、読み取られたか、閉じられたかを知ることができます。 次に、このディレクトリツリーでイベントを検出すると、この情報を使用して他のプログラムを実行します。たとえば、プロセスがこのディレクトリツリーのファイルを削除したときにユーザーに警告できます。
4. inotifyイベントを理解する
Linuxでは、 inotify インターフェイスを使用して、ディレクトリまたはファイルを監視できます。 これを行うには、ディレクトリまたはファイルにウォッチを追加します。 ファイルに時計を追加すると、それを監視できます。 たとえば、プロセスがファイルを開いたり、変更したり、読み取ったり、閉じたり、移動したり、削除したりするタイミングがわかります。 ディレクトリにウォッチを追加すると、そのディレクトリ内のファイル内のイベントも監視されます。 さらに、別のプロセスがそのディレクトリ内のファイルを作成、削除、または移動したかどうかを知ることができます。 すべてのイベントを監視するか、一部のイベントのみを監視するかを選択できます。 これらのイベントのいずれかが発生すると、システムから通知されます。
5. inotifywaitを使用する
inotifywaitコマンドを使用してディレクトリツリーを監視できます。サブディレクトリを含むディレクトリツリーを監視するには、-rパラメータを使用します。 また、-mパラメーターを使用する必要があります。 これにより、inotifywaitがディレクトリを永久に監視し続けるように構成されます。 それ以外の場合、inotifywaitは最初のイベントの後に終了します。 メインディレクトリ内のイベントを監視する方法を見てみましょう:
$ inotifywait -m -r main
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
これにより、 inotifywait コマンドは引き続きフォアグラウンドで実行され、イベントを待機します。 ここで、 inotifywait がまだ実行されている間に、新しいシェルを開いて echo example> main / 1/2 /file1を実行してみましょう。 このコマンドは、 main / 1/2フォルダー内に新しいファイルを作成します。inotifywait を実行するシェルに戻り、出力を確認します。
main/1/2/ CREATE file1
main/1/2/ OPEN file1
main/1/2/ MODIFY file1
main/1/2/ CLOSE_WRITE,CLOSE file1
inotifywaitの出力には3つの列があることがわかります。 最初にベースディレクトリ、次にイベント、最後にそのイベントをトリガーしたファイル。 それでは、 main /2ディレクトリ内に1という新しいフォルダを作成しましょう。 次に、新しいディレクトリ内にfile1という名前の新しいファイルを作成します。
$ mkdir main/2/1
$ echo example > main/2/1/file1
inotifywaitの出力を見てみましょう。
main/2/ CREATE,ISDIR 1
main/2/ OPEN,ISDIR 1
main/2/ ACCESS,ISDIR 1
main/2/ CLOSE_NOWRITE,CLOSE,ISDIR 1
main/2/1/ CREATE file1
main/2/1/ OPEN file1
main/2/1/ MODIFY file1
main/2/1/ CLOSE_WRITE,CLOSE file1
inotifywaitが新しいディレクトリのイベントを自動的に監視していることがわかります。 最後に、監視するイベントを正確に指定する方法を見てみましょう。これを行うには、 -e パラメーターを使用して、目的のイベントをコンマで区切って追加します。 まず、前のinotifywaitコマンドをControl+Cで終了しましょう。 次に、作成イベントと変更イベントのみを監視しましょう。
$ inotifywait -m -r -e create,modify main
次に、 main / 1/2 / file1 ファイルに書き込み、 main /1/2ディレクトリ内にfile2という新しい空のファイルを作成します。
$ echo example2 >> main/1/2/file1
$ touch main/1/2/file2
新しい出力を見てみましょう:
main/1/2/ MODIFY file1
main/1/2/ CREATE file2
6. inotifywait出力を別のスクリプトと統合する
これまで、使い方を学びました
$ file_removed() {
xmessage "$2 was removed from $1" &
}
この関数は2つのパラメーターを受け取ります。 1つはディレクトリで、もう1つは削除されたファイルです。 また、バックグラウンドで xmessage を実行するため、関数はブロックされません。 次に、ファイルが変更および作成されたときにログファイルに書き込む2つの関数を記述しましょう。
$ file_modified() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was modified" >> monitor_log
}
$ file_created() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was created" >> monitor_log
}
これで、 inotifywait 出力を解析して、whileループに送ることができます。 read コマンドを使用して、出力からディレクトリ、イベント、およびファイルフィールドを分割します。 次に、 case コマンドを使用して、イベントに応じて呼び出す関数を決定できます。 さらに、-qパラメーターをinotifywaitコマンドに追加して、inotifywaitが最初のメッセージを出力せずにイベントのみを出力するようにします。 これらすべてを、というスクリプトにまとめましょう。
#!/bin/bash
file_removed() {
xmessage "$2 was removed from $1" &
}
file_modified() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was modified" >> monitor_log
}
file_created() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was created" >> monitor_log
}
inotifywait -q -m -r -e modify,delete,create $1 | while read DIRECTORY EVENT FILE; do
case $EVENT in
MODIFY*)
file_modified "$DIRECTORY" "$FILE"
;;
CREATE*)
file_created "$DIRECTORY" "$FILE"
;;
DELETE*)
file_removed "$DIRECTORY" "$FILE"
;;
esac
done
最初にバックグラウンドでmonitor_directory_tree.shを実行して、このスクリプトをテストしてみましょう。 次に、 main /3/2/1ディレクトリを削除します。 次に、 main / 1/2 /file1ファイルにテキストを書き込みます。 最後に、 main /file1ファイルを作成して書き込みます。
$ ./monitor_directory_tree.sh main &
[1] 4800
$ rm -r main/3/2/1
$ echo example >> main/1/2/file1
$ echo example >> main/file1
これにより、2つのxmessageアラートが表示されたことがわかります。 1つのアラートは「1がmain/3/2/1から削除されました」と言い、もう1つのアラートは「1がmain/3/2/1から削除されました」と言います。 これは、 rm -r main / 3/2/1、を実行すると、 main /3/2/1/1サブディレクトリも削除されたためです。 それでは、monitor_logファイルを見てみましょう。
$ cat monitor_log
[Tue Sep 21 21:49:31 -03 2021]: The file main/1/2/file1 was modified
[Wed Sep 21 21:49:34 -03 2021]: The file main/file1 was created
[Wed Sep 21 21:49:34 -03 2021]: The file main/file1 was modified
ご覧のとおり、ログには main / 1/2 /file1を変更したことが示されています。 次に、ファイル main / file1 が作成され、変更されたことを示します。
7. 結論
この記事では、ディレクトリツリーを監視する方法を説明しました。 inotifyインターフェースの紹介を最初に見ました。 次に、 inotifywait を使用して、ディレクトリとそのサブディレクトリ内のイベントを監視する方法を確認しました。 そして最後に、inotifywait出力を他のスクリプトと統合する方法を学びました。