web-dev-qa-db-ja.com

Linuxでディレクトリの内容が変更されたときにスクリプトを自動的に実行する方法は?

新しいファイルが特定のディレクトリにコピーされるたびにスクリプトを自動的に実行したい。言い換えれば、Linuxでディレクトリの変更を「監視」し、変更に応じて何かを実行する方法はありますか?

17
GeneQ

幸運なことにdebianベースのディストリビューションを利用している場合は、apt-get install dnotify。他のディストリビューションもおそらく似たようなものがあります-dnotifyの名前を探してください。

dnotifyは、Linuxカーネル2.4.19以降のdnotify APIに基づくシンプルなプログラムです。 dnotifyは、特定のディレクトリの内容が変更されるたびに、指定されたコマンドを実行できます。コマンドラインから実行され、2つの引数を取ります。監視する1つ以上のディレクトリと、ディレクトリが変更されるたびに実行するコマンドです。オプションは、トリガーするイベントを制御します。ファイルがディレクトリで読み取られたとき、ファイルが作成されたとき、削除されたときなどです。

これを独自のプログラム内で処理したい場合は、dnotifyも使用したいAPIです。

17
MikeyB

このようなinotify-toolsでスクリプトを実行できます。変更されたファイル、新しいファイル、および削除されたファイルの変更についてディレクトリを監視し、スクリプトを実行します。

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done
12
user7119

incron は基本的にあなたが望むものだと思います。通知メカニズムとしてinotifyを使用しますが(他の人が指摘したように、dnotifyに優先します)、inotifywaitなどを使用して継続的に実行するスクリプトは必要ありません(もちろん、incronデーモンは常に実行されています)。システム全体の「crontabs」およびユーザー「crontabs」は、標準のcronと同様にサポートされますが、トリガーとして時間を指定するのではなく、inotifyイベントとファイル/ディレクトリ名が使用されます。

incronはUbuntuやDebianを含む多くのディストリビューション向けにパッケージ化されていると思います。

4
Andrew Ferrier

entr は、私が見た中で最もシンプルで最も構成可能なファイル通知ツールです。その使用は、ディレクトリではなくファイルの監視に向けて最適化されていますが、ケースを解決することもできます。

追加されたファイルを検出して操作するには、それを他のツール(例: makeentrは名前などを送信せず、実行するように指定したものを実行するだけです。

ディレクトリに追加されたファイルを確認するには:

_## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done
_

既存のファイルが変更されたときにも動作したい場合:

_## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done
_

...そして、ファイルが追加されるとfind式が再び実行されるため、ループメカニズムが役立ちます。

より優れたエラー処理が必要で、追加/削除されたファイルごとに1回だけ実行されるようにしたい場合は、少しおかしなことになりますが、これらの単純なケースでは見事です。


編集:incronのようなシステムレベルでこれを行う場合は、スクリプトをお気に入りのプロセスマネージャーに追加します(- s6runitsystemd または sysvinit でループをスキップします。

_#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)
_

execとプロセス置換(<(...))は、シグナルを適切に処理するために(つまり、シェルを邪魔にならないようにするために)プロセスマネージャから実行する場合に重要です。

0
clacke

この目的のためだけのソフトウェアがあります autoenv 確認した方がいいかもしれません。

0
DukeLion