web-dev-qa-db-ja.com

ファイルが変更されたときにスクリプト/プログラムを実行する

ファイルにトリガーのようなものを設定して、ファイルが変更されるたびにスクリプトまたはプログラムが実行されるようにする方法はありますか?

シェルスクリプト内でこのメカニズムを見つけただけですが、オペレーティングシステムベースでそのメカニズムがあるかどうかを知りたいのです(バックグラウンドプログラムを手動で実行する必要がないように)。オペレーティングシステムベースのソリューションは、数秒ごとに実行されるcronジョブですが、これは私には適切なソリューションのようには見えません。

ところで、Debian用です。

手伝ってくれてありがとう。

6
cyphorious

オプションの1つは、Linuxカーネルの inotify サブシステムです。

inotifyは、ファイルシステムを拡張してファイルシステムの変更を通知し、それらの変更をアプリケーションに報告するように機能するLinuxカーネルサブシステムです。

しかし、inotifyはカーネルランドであるため、実際に使用するにはユーザースペースに何かが必要です。

Inotify cronデーモン(incrond)は、ファイルシステムイベントを監視し、システムテーブルとユーザーテーブルで定義されたコマンドを実行するデーモンです。その使用法は一般的にcron(8)に似ています。

Gaminは、FAMのサブセットであるFile AlterationMonitorを独立して実装するファイルとディレクトリの監視システムです。サービスとして実行すると、ファイルまたはディレクトリへの変更を検出できます。 gam_serverは、Gaminのデーモンとして機能します。

inoticoming-ファイルが着信ディレクトリにヒットしたときにアクションをトリガーします

askubuntuに関する同様の質問に対する回答がありました:

https://askubuntu.com/a/43848/122

8
akira

これを行うもう1つの手っ取り早い方法は、inotify-toolsパッケージ(Fedora上)のinotifywaitを使用することです。

単一のbashコマンドラインからすべてを実行できるため、この方法の方が好きです。小さなプログラムを書いているときに、保存したものの結果を確認するためにこれをよく使用します。

while [[ 1 ]]; do inotifywait -e modify <filename>; make && ./helloworld; done
2
marioux

シェルスクリプト内のこのメカニズムは完全に適切なソリューションであり、そのメカニズムであると私は主張します。オペレーティングシステムベースで(バックグラウンドプログラムを手動で実行する必要がないように)は、そのソリューションを s6 のようなプロセスマネージャーに配置することを意味します。 )、 runitsystemd unit 、または inittabエントリ の場合あなたはsysvinitシステムを使用しています。

それを実行し続けるためのメカニズムに関係なく、私はファイルを監視するための entr が好きです。シンプルで、要点を言えば、構成可能です(たとえば、プロセスマネージャーを配置するのは簡単です)。

/path/to/fileを監視し、変更されたときに/usr/local/bin/do_stuffを実行するためのスクリプトは次のとおりです。

#!/bin/bash
exec entr /usr/local/bin/do_stuff < <(echo /path/to/file)

これですべてです。それをrunitまたはs6のrunファイルに入れるか、systemdユニットのExecStart行に入れるか、inittabの行からそのスクリプトを呼び出します。 inittabに入れる場合は、おそらくどこかにsleepを追加する必要がありますが、sysvinitは、スペルミスやファイルの欠落などが原因ですぐに失敗するプロセスをレート制限しないためです。


なぜecho /path/to/file | entr /usr/local/bin/do_stuffだけではないのですか?プロセス管理の下で実行する場合、管理対象プロセスがスーパーバイザーの直下にあることが重要です。これにより、たとえば、シャットダウン。シェルがスーパーバイザーの下で実行されている場合、シェルは実行中のプロセスではなく、TERMINT、またはKILLシグナルをキャッチし、それらを渡しません。 。または、終了してプロセスを孤立させたままにします。 execは、プロセスチェーンからシェルを削除します。 (|の右側にあるexecは違いがありません)

または、自分自身を真ん中に置くことのないシェルを使用します execline

#!/bin/execlineb
pipeline -d {
  echo /path/to/file
} entr /usr/local/bin/do_stuff
1
clacke