it-swarm-ja.com

ファイルが変更されたときにコマンドを実行する方法

ファイルが変更されたときにコマンドを実行するための迅速で簡単な方法が欲しいのです。非常に単純なもの、つまり端末上で実行したままにしておき、そのファイルの処理が終わったらいつでも閉じたいものが欲しいのです。

現在、私はこれを使っています:

while read; do ./myfile.py ; done

それから私はそのターミナルに行き、押す必要があります Enter私のエディタでそのファイルを保存するときはいつでも。私が欲しいのはこのようなものです。

while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done

またはそれと同じくらい簡単な他の解決策。

ところで:私はVimを使用しています、そしてBufWrite上で何かを実行するためにautocommandを追加できることは知っていますが、これは私が今望んでいるような解決策ではありません。

更新:シンプルで、できれば破棄できるものが欲しいのですが。さらに、プログラムの出力を見たいので(エラーメッセージを見たいのですが)、端末で何かを実行したいのです。

回答について:あなたのすべての答えてくれてありがとう!それらはすべて非常に優れており、それぞれが他のものとは非常に異なるアプローチを取ります。私は1つだけを受け入れる必要があるので、私はそれが最もエレガントではないことを知っていても、私は実際に使ったものを受け入れています(それは単純で、素早く、覚えやすいものでした)。

418

inotifywait を使って簡単に(ディストリビューションのinotify-toolsパッケージをインストールします):

while inotifywait -e close_write myfile.py; do ./myfile.py; done

または

inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
  ./myfile.py         # or "./$filename"
done

最初のスニペットは単純ですが、重大な欠点があります。inotifywaitが実行されていない間(特にmyfileが実行されている間)に行われた変更が失われる可能性があります。 2番目のスニペットにはこの問題はありません。ただし、ファイル名に空白が含まれていないと想定していることに注意してください。それが問題であるならば、ファイル名を含まないように出力を変更するために--formatオプションを使います:

inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
  ./myfile.py
done

いずれにせよ、制限があります。あるプログラムが既存のmyfileに書き込むのではなくmyfile.pyを別のファイルに置き換えると、inotifywaitは死にます。多くの編集者がそのように機能します。

この制限を克服するには、ディレクトリにinotifywaitを使用します。

inotifywait -e close_write,moved_to,create -m . |
while read -r directory events filename; do
  if [ "$filename" = "myfile.py" ]; then
    ./myfile.py
  fi
done

あるいは、 incron (ファイルが変更されたときにイベントを登録させる)や fswatch のような基本的な機能を使用する別のツールを使用します。 Linuxのinotifyの各変種のアナログを使用して、他の多くのUnixの変種でも動作するツール。

389
Gilles

entrhttp://entrproject.org/ )はinotifyにもっとわかりやすいインターフェースを提供します(そして* BSDとMac OS Xもサポートしています。

複数のファイルを監視するように指定するのが非常に簡単になり(ulimit -nによってのみ制限されます)、置き換えられるファイルを扱う手間が省け、bash構文も少なくて済みます。

$ find . -name '*.py' | entr ./myfile.py

私は現在修正しているコードのユニットテストを実行するために私のプロジェクトソースツリー全体でそれを使用してきました、そしてそれはすでに私のワークフローへの大きな後押しでした。

-c(実行の合間に画面をクリアする)や-d(監視対象のディレクトリに新しいファイルが追加されたときに終了する)のようなフラグは、さらに柔軟性を高めます。例えば、次のようにします。

$ while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done

2018年初めの時点で、まだ活発に開発が行われており、Debian&Ubuntu(apt install entr)にあります。いずれにせよ、著者のレポから構築するのは苦労しませんでした。

154
Paul Fenney

私はこれを正確に行うためにPythonプログラムを書いて、 when-changed と呼びました。

使い方は簡単です。

when-changed FILE COMMAND...

複数のファイルを見るには

when-changed FILE [FILE ...] -c COMMAND

FILEはディレクトリにすることができます。 -rを使って再帰的に監視します。ファイル名をコマンドに渡すには、%fを使用します。

105
joh

このスクリプトはどうですか?ファイルのアクセス時間を取得するためにstatコマンドを使用し、アクセス時間に変更があるときはいつでも(ファイルがアクセスされるときはいつでも)コマンドを実行します。

#!/bin/bash

### Set initial time of file
LTIME=`stat -c %Z /path/to/the/file.txt`

while true    
do
   ATIME=`stat -c %Z /path/to/the/file.txt`

   if [[ "$ATIME" != "$LTIME" ]]
   then    
       echo "RUN COMMAND"
       LTIME=$ATIME
   fi
   sleep 5
done
48
VDR

Vimを使った解決策:

:au BufWritePost myfile.py :silent !./myfile.py

しかし、私はこの解決策を望みません。なぜなら、それはタイプするのがちょっと面倒で、タイプするものを正確に覚えるのは少し難しいし、その効果を元に戻すのは少し難しいからです(:au! BufWritePost myfile.pyを実行する必要があります)。さらに、このソリューションはコマンドが実行を終了するまでVimをブロックします。

他の人に役立つかもしれないので、私は完全を期してこのソリューションをここに追加しました。

プログラムの出力を表示するには(Enterキーを押すまで出力がエディタに数秒間上書きされるため、編集フローを完全に中断します)、:silentコマンドを削除します。

30

npm がインストールされている場合は、 nodemon がおそらく最も簡単な方法です。特にOS Xでは、inotifyツールを持っていないようです。フォルダが変更されたときにコマンドを実行することをサポートします。

23
davidtbernal

rerun2on github )は、10行の形式のBashスクリプトです。

#!/usr/bin/env bash

function execute() {
    clear
    echo "[email protected]"
    eval "[email protected]"
}

execute "[email protected]"

inotifywait --quiet --recursive --monitor --event modify --format "%w%f" . \
| while read change; do
    execute "[email protected]"
done

GithubのバージョンをPATHに 'rerun'として保存し、次のようにしてそれを起動します。

rerun COMMAND

現在のディレクトリ内にファイルシステムの変更イベントがあるたびにCOMMANDを実行します(再帰的)。

それについて好むかもしれないもの:

  • それはinotifyを使用します、従ってポーリングより敏感です。毎回サブミリ秒の単体テストを実行したり、保存するたびにgraphvizドットファイルをレンダリングするのに最適です。
  • 高速なので、パフォーマンス上の理由から(node_modulesのような)大きなサブディレクトリを無視するように指示する必要はありません。
  • 起動時に実行するのではなく、inotifywaitを1回呼び出すだけで、繰り返しを実行するたびにウォッチを確立するというコストのかかるヒットが発生するため、非常に応答性に優れています。
  • それはちょうど12行のBashです
  • これはBashなので、渡されたコマンドは、Bashプロンプトで入力した場合とまったく同じように解釈されます。 (おそらく他のシェルを使っているならこれはクールではないでしょう。)
  • このページの他のinotifyソリューションとは異なり、COMMANDの実行中に発生したイベントは失われません。
  • 最初のイベントでは、0.15秒間「デッドピリオド」に入ります。その間、他のイベントは無視され、COMMANDは1回だけ実行されます。これは、バッファを保存するときにViやEmacsが実行するcreate-write-moveダンスによって引き起こされる一連のイベントが、実行速度の遅いテストスイートを何度も実行することを避けるためです。 COMMANDの実行中に発生したイベントは無視されません。これらのイベントは2回目のデッドピリオドとそれに続く実行を引き起こします。

嫌いなことがあるかもしれません。

  • Inotifyを使っているので、Linuxland以外では動きません。
  • Inotifyを使用しているので、ユーザーのinotifyウォッチの最大数より多くのファイルを含むディレクトリを見ようとするのを妨げます。デフォルトでは、これは私が使用するさまざまなマシンでおよそ5,000から8,000に設定されているようですが、増やすのは簡単です。 https://unix.stackexchange.com/questions/13751/kernel-inotify-watch-limit-reached を参照してください。
  • Bashエイリアスを含むコマンドの実行に失敗します。私はこれが機能していたことを誓うことができました。原則として、これはBashであり、COMMANDをサブシェルで実行していないため、これが機能することを期待しています。誰もがなぜそれがしないのか知っているなら私は聞きたいです。このページの他の解決策の多くはそのようなコマンドも実行できません。
  • 個人的には、自分が実行している端末のキーを押して手動でCOMMANDを追加実行させることができればと思います。単純にこれを追加できますか。同時に実行する 'while read -n1'ループも実行するのですか。
  • 現在のところ、端末をクリアし、実行のたびに実行されたCOMMANDを出力するようにコーディングしました。このようなことを無効にするためにコマンドラインフラグを追加することを好む人もいますが、これはサイズと複雑さを何倍も増加させるでしょう。

これは@ cychoiの回答の改良です。

15

私のようにinotify-toolsをインストールできない人のために、これは役に立ちます。

watch -d -t -g ls -lR

出力が変更されるとこのコマンドは終了します。ls -lRはすべてのファイルとディレクトリをそのサイズと日付とともに一覧表示します。

-g, --chgexit
          Exit when the output of command changes.

私はこの答えが誰にも読まれないかもしれないことを知っています、しかし私は誰かがそれに達することを望みます。

コマンドラインの例:

~ $ cd /tmp
~ $ watch -d -t -g ls -lR && echo "1,2,3"

別の端末を開く:

~ $ echo "testing" > /tmp/test

最初の端末は1,2,3を出力します

簡単なスクリプトの例:

#!/bin/bash
DIR_TO_WATCH=${1}
COMMAND=${2}

watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}
13
Sebastian

これは、単純なShell Bourne Shellスクリプトです。

  1. 2つの引数を取ります。監視対象のファイルとコマンド(必要に応じて引数付き)です。
  2. 監視しているファイルを/ tmpディレクトリにコピーします。
  3. 監視しているファイルがコピーより新しいかどうかを確認するために2秒ごとにチェックします
  4. 新しい場合は新しいコピーで上書きしてコマンドを実行します
  5. Ctr-Cを押すと自動的にクリーンアップされます

    #!/bin/sh  
    f=$1  
    shift  
    cmd=$*  
    tmpf="`mktemp /tmp/onchange.XXXXX`"  
    cp "$f" "$tmpf"  
    trap "rm $tmpf; exit 1" 2  
    while : ; do  
        if [ "$f" -nt "$tmpf" ]; then  
            cp "$f" "$tmpf"  
            $cmd  
        fi  
        sleep 2  
    done  
    

これはFreeBSD上で動作します。私が考えることができる唯一の移植性の問題は、他のUNIXがmktemp(1)コマンドを持っていない場合ですが、その場合は一時ファイル名をハードコードすることができます。

12
MikeyMike

incron をご覧ください。これはcronに似ていますが、時間の代わりにinotifyイベントを使用します。

8
Florian Diesch

NodeJを使った別の解決法は、fsmonitorです。

  1. インストール

    Sudo npm install -g fsmonitor
    
  2. コマンドラインから(例:ログを監視し、1つのログファイルが変更された場合は「製品版」)

    fsmonitor -s -p '+*.log' sh -c "clear; tail -q *.log"
    
6
Atika

特にこのプラグインで、Guardを調べてください。

https://github.com/hawx/guard-Shell

プロジェクトのディレクトリにあるパターンをいくつでも監視し、変更があったときにコマンドを実行するように設定できます。そもそもあなたがやろうとしていることのために利用可能なプラグインがあるという可能性も十分にあります。

6

Linuxの場合

man watch

watch -n 2 your_command_to_run

2秒ごとにコマンドを実行します。

コマンドの実行に2秒以上かかる場合、watchはそれが完了するまで待ってから再度実行します。

6
Eric Leschinski

nodemon がインストールされている場合は、次のようにします。

nodemon -w <watch directory> -x "<Shell command>" -e ".html"

私の場合は、HTMLをローカルで編集し、ファイルが変更されたときにそれをリモートサーバーに送信します。

nodemon -w <watch directory> -x "scp filename [email protected]:/var/www" -e ".html"
5
Jay

ウォッチドッグはPythonプロジェクトです。

対応プラットフォーム

  • Linux 2.6(inotify)
  • Mac OS X(FSEvents、kqueue)
  • FreeBSD/BSD(kqueue)
  • Windows(I/O完了ポートを持つReadDirectoryChangesW、ReadDirectoryChangesWワーカースレッド)
  • OSに依存しない(ディレクトリのスナップショットを探すためにディスクをポーリングし、それらを定期的に比較する。遅くて推奨されない)

そのためのコマンドラインラッパーを書いただけですwatchdog_exec

実行例

現在のディレクトリ内のファイルやフォルダを含むfsイベントで、fsイベントが変更されていない限りecho $src $dstコマンドを実行してから、python $srcコマンドを実行します。

python -m watchdog_exec . --execute echo --modified python

短い引数を使用し、イベントに "main。py"が含まれる場合にのみ実行するように制限します。

python -m watchdog_exec . -e echo -a echo -s __main__.py

編集:Watchdogにはwatchmedoという正式なCLIがあることがわかったので、それも調べてください。

5
Samuel Marks

あなたのプログラムがある種のログ/出力を生成するなら、あなたはあなたのスクリプトに依存するそのログ/出力のための規則でMakefileを作成することができ、そして以下のようなことをすることができます。

while true; do make -s my_target; sleep 1; done

別の方法として、偽のターゲットを作成し、それに対するルールでスクリプトを呼び出して偽のターゲットに触れることもできます(それでもスクリプトに依存します)。

4
ctgPi

Gillesの答え を改善しました。

このバージョンは一度inotifywaitを実行し、その後イベント(.e.g .: modify)を監視します。そのようなinotifywaitは、発生したすべてのイベントで再実行する必要はありません

それは速くて速いです!(大きなディレクトリを再帰的に監視する場合でも)

inotifywait --quiet --monitor --event modify FILE | while read; do
    # trim the trailing space from inotifywait output
    REPLY=${REPLY% }
    filename=${REPLY%% *}
    # do whatever you want with the $filename
done
4
cychoi

swarminglogic は、 watchfile.sh というスクリプトを書き、 GitHub Gist として入手可能です。

4

もう少しプログラミング側ですが、 inotify のようなものが必要です。 jnotifypyinotify のように、多くの言語で実装されています。

このライブラリを使用すると、単一のファイルまたはディレクトリ全体を監視でき、アクションが検出されたときにイベントを返します。返される情報には、ファイル名、アクション(作成、変更、名前変更、削除)、およびファイルパスなどの有用な情報が含まれています。

3
John T

私はwhile inotifywait ...; do ...; doneの単純さが好きですが、それには2つの問題があります。

  • do ...;の間に行われたファイルの変更は見逃されます
  • 再帰モードで使用すると遅くなります

そのため、制限なしでinotifywaitを使用するヘルパースクリプトを作成しました。 inotifyexec

~/bin/のように、このスクリプトを自分のパスに入れることをお勧めします。使い方はコマンドを実行するだけで説明されます。

例:inotifyexec "echo test" -r .

3
Wernight

watchコマンドを使用して Sebastianの解決策 を改善しました。

watch_cmd.sh

#!/bin/bash
WATCH_COMMAND=${1}
COMMAND=${2}

while true; do
  watch -d -g "${WATCH_COMMAND}"
  ${COMMAND}
  sleep 1     # to allow break script by Ctrl+c
done

例を呼び出します。

watch_cmd.sh "ls -lR /etc/nginx | grep .conf$" "Sudo service nginx reload"

うまくいきますが注意してください:watchコマンドには既知のバグがあります(manを参照):-g CMD出力の末尾部分のVISIBLEの変更にのみ反応します。

3
alex_1948511

FreeBSDのソリューションを探している人のために、ここにportがあります。

/usr/ports/sysutils/wait_on
3
akond

あなたは 反射 を試すことができます。

Reflexは、ディレクトリを監視し、特定のファイルが変更されたときにコマンドを再実行するための小さなツールです。コンパイル/ lint/testタスクを自動的に実行したり、コードが変更されたときにアプリケーションをリロードしたりするのに最適です。

# Rerun make whenever a .c file changes
reflex -r '\.c$' make
2
masterxilo

OS Xを使っている人は、LaunchAgentを使ってパスやファイルの変更を監視し、それが起こったときに何かをすることができます。参考までに - LaunchControlはデーモン/エージェントを簡単に作成/変更/削除するのに良いアプリです。

ここから取られた例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.Apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>
        <string>say</string>
        <string>yy</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>~/Desktop/</string>
    </array>
</dict>
</plist>
1
Hefewe1zen

私はこのための要旨を持っています、そして使い方はとても簡単です。

watchfiles <cmd> <paths...>

https://Gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55

1
thiagoh

私はそれをするのにこのスクリプトを使います。 inotifyをモニタモードで使っています

#!/bin/bash
MONDIR=$(dirname $1)
ARQ=$(basename $1)

inotifywait -mr -e close_write $MONDIR | while read base event file 
do
  if (echo $file |grep -i "$ARQ") ; then
    $1
  fi
done

Runatwrite.shとして保存してください。

Usage: runatwrite.sh myfile.sh

書き込みごとにmyfile.shが実行されます。

1
Fernando Silva

私がファイルの変更を追跡するために使っているのは厄介な答えです。

$ while true ; do NX=`stat -c %Z file` ; [[ $BF != $NX ]] && date >> ~/tmp/fchg && BF=$NX || sleep 2 ; done

最初の日付が開始時刻であることがわかっていれば、BFを初期化する必要はありません。

これはシンプルで移植性があります。ここでスクリプトを使用して同じ戦略に基づくもう一つの答えがあります。また見てください。


使用法:これを使ってデバッグし、~/.kde/share/config/plasma-desktop-appletsrcを監視します。何らかの理由で私のSwitchTabsOnHover=falseを失い続けること

1
Dr Beco

基本的な使い方

これ以上のソフトウェアをインストールする必要がなく、箱から出して動作するソリューションです。

tail -q --follow=name myfile.txt | head -n 0

このコマンドは以下の条件で終了します。

  • コマンド実行後にmyfile.txtに1行追加されます。
  • myfile.txtは、コマンドの実行後に別のものに置き換えられます

あなたはあなたがvimを使っていると言います、そしてvimは保存時にファイルを置き換えます。私はこれをvimでテストしました。

このコマンドの出力は無視してかまいません。

tail: 'myfile.txt'は置き換えられました。新しいファイルの末尾に続く

高度な使い方

これをtimeoutと組み合わせてtrueまたはfalseを返すことができます。あなたはこのようにそれを使うことができます:

タイムアウト5秒bash -c 'tail -q --follow =名前パイプ2>/dev/null | head -n 0 '&& echoが変更されました||エコータイムアウト

討論

tailはフードの下でinotifyを使用します。これが、あなたがポーリングなしでこの空想的な非同期の振る舞いをする方法です。おそらく他のinotifyを使った標準的なunixプログラムがあります。

これらのコマンドはすぐに終了することがありますが、2度目に実行した場合は、アドバタイズされたとおりに機能します。どこかに1つずつエラーを出しました。これを修正してください。

RHEL上で私は使用することができます:

タイムアウト5秒sh -c 'gioモニターパイプhead -n 0 '&& echoが変更されました||エコータイムアウト

しかし、それが移植可能かどうかはわかりません。

0

findがトリックをやることができます。

while true; do
    find /path/to/watched/file -ctime 1s | xargs do-what-you-will
done

最後のfind -ctime 1s変更された場合、1sはファイル名を表示します。

0
lvijay

'fido'ツールは、この必要性のためのさらに別の選択肢かもしれません。 https://www.joedog.org/fido-home/ を参照してください。

0
David Ramirez

特定の ファイルへの変更のためにグーグルによってこれを見つける人のために、答えははるかに簡単です( ジルの答え に触発されて)。

もしあなたが何かをしたいのであれば - /特定のファイルに書き込まれた後、これは次の通りです:

while true; do
  inotifywait -e modify /path/to/file
  # Do something *after* a write occurs, e.g. copy the file
  /bin/cp /path/to/file /new/path
done

これを、例えばcopy_myfile.shとして保存し、.shファイルを/etc/init.d/フォルダーに入れて、起動時に実行できるようにします。

0
LondonRob

他にもいくつか行ったように、これを行うための軽量のコマンドラインツールも書いています。完全に文書化され、テストされ、そしてモジュール化されています。

Watch-Do

Installation

あなたはそれをインストールすることができます(あなたがPython3とpipを持っているなら):

pip3 install git+https://github.com/vimist/watch-do

使用法

実行してすぐにそれを使用する:

watch-do -w my_file -d 'echo %f changed'

機能の概要

  • ファイルのグロビングをサポートします(-w '*.py'または-w '**/*.py'を使用)
  • ファイル変更時に複数のコマンドを実行する(もう一度-dフラグを指定するだけ)
  • グロビングが使用されているかどうかを監視するファイルのリストを動的に管理します(これを有効にするには-r
  • ファイルを「見る」ための複数の方法:
    • 修正時間(デフォルト)
    • ファイルハッシュ
    • 自分で実装するのは簡単(これは ModificationTime ウォッチャーです)
  • モジュール設計。ファイルにアクセスしたときにコマンドを実行したい場合は、独自のウォッチャー(doerを実行するかどうかを決定するメカニズム)を書くのが簡単です。
0
vimist

私は rerun と呼ばれる、これを正確に行うためのPythonプログラムを書きました。

更新:この答えは変更をポーリングするPythonスクリプトです。これは状況によっては便利です。 inotifyを使用するLinux専用のBashスクリプトについては、私の他の答えを見て、このページで 'rerun2'を検索してください。

Python 2またはPython 3にインストールするには、

pip install --user rerun

使い方はとても簡単です。

rerun "COMMAND"

このコマンドは、空白で区切られた一連の引数ではなく、単一の引数として想定されています。したがって、示されているとおりに引用してください。これにより、追加する必要のある余分なエスケープが減少します。コマンドラインで入力したのと同じように、引用符で囲んでコマンドを入力します。

デフォルトでは、カレントディレクトリ内またはその下にあるすべてのファイルを監視し、既知のソース管理ディレクトリ、.git、.svnなどをスキップします。

オプションのフラグには、名前付きファイルまたはディレクトリへの変更を無視する '-i NAME'が含まれます。これは複数回指定できます。

これはPythonスクリプトなので、コマンドをサブプロセスとして実行する必要があります。ユーザーの現在のシェルの新しいインスタンスを使用して「COMMAND」を解釈し、実際に実行するプロセスを決定します。ただし、コマンドに.bashrcで定義されているシェルエイリアスなどが含まれている場合、これらはサブシェルによって読み込まれません。これを修正するために、対話的な(別名 'login')サブシェルを使うために '-I'フラグを再実行することができます。通常のシェルを起動するよりも遅く、エラーが発生しやすくなります。なぜなら、それはあなたの.bashrcを読み込む必要があるからです。

私はPython 3でそれを使っていますが、最後に私がチェックしたのはPython 2でも動いています。

両刃の刀は、それがinotifyの代わりに投票を使うということです。逆に言えば、これはすべてのOSで動作するということです。加えて、変更されたファイルごとに一度だけではなく、ファイルシステムの変更に対して一度だけ指定されたコマンドを実行するという点で、ここに示された他の解決策より優れています。コマンド実行中.

不利な点として、ポーリングは0.0から1.0秒の待ち時間があることを意味し、もちろん非常に大きなディレクトリを監視するのは遅いです。とは言っても、virtualenvやnode_modulesのような大きなものを無視するために '-i'を使用する限り、これが目立つほど大きなプロジェクトに遭遇したことはありません。

うーん。 rerunは何年もの間不可欠でした - 私は基本的にテストを実行したり、ドットファイルを編集しながらドットファイルを再構築したりするために毎日8時間使用しています。 inotifyを使用し(私はもうWindowsやOSXを使用していません。)、Bashで書かれているソリューションです(だから、余分な手間をかけずにエイリアスで動作します)。

0

説明

これはファイルの変更を監視し、どんなコマンドでも実行します(さらなる引数を含む) 2番目のステートメントとして与えられたそれはまたスクリーンをクリアしそして最後の実行の時間を印刷するでしょう。注:各whileループサイクルの後に関数がスリープする秒数を変更することで、関数をより反応性にすることができます。

使用例

watch_file my_file.php php my_file.php

この行はphpファイルのmy_file.phpを監視し、それが変わるたびにphpインタプリタを実行します。


関数定義

function watch_file (){

### Set initial time of file
LTIME=`stat -c %Z $1`
printf "\033c"
echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
${@:2}

while true
do
   ATIME=`stat -c %Z $1`

   if [[ "$ATIME" != "$LTIME" ]]
   then
    printf "\033c"
    echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
    ${@:2}
    LTIME=$ATIME
   fi
   sleep 1
done
}

クレジット

これは基本的にVDRの答えのより一般的なバージョンです。

0
petermeissner

ちょっと違う状況がありました。しかし、私はこれがこの質問を読んでいる人には役に立つかもしれないと感じます。

ログファイルのサイズが変更されたときに通知を受ける必要がありましたが、すぐには必要ありませんでした。そしてそれは将来的には数日あるいは数週間になるかもしれないので、私はinotify(とにかくそのサーバーにインストール/起動されていない)をコマンドラインで使うことができませんでした(Nohupなどは使いたくありません)。それで私はチェックするためにcronでbashスクリプトを実行することにしました

スクリプトは監視されているファイルのファイルサイズをテキストファイルに書き込み、cronを実行するたびにその値が変更されているかどうかをチェックし、変更されている場合は最後の行を私にメールします。

#!/bin/bash
FILE_TO_WATCH="/path/to/log_file.log"
FILESIZE_FILE="/path_to/record.txt"
SUBJECT="Log file 'log_file.log' has changed"
MAILTO="[email protected]"
BODY="Last line of log file:\n"
LAST_LINES=1

# get old recorded file size from file
OLD_FILESIZE=$(cat "${FILESIZE_FILE}")
# write current file size into file
stat --printf="%s" "${FILE_TO_WATCH}" > "${FILESIZE_FILE}"
# get new recorded file size from file
NEW_FILESIZE=$(cat "${FILESIZE_FILE}")


if [ "${OLD_FILESIZE}" != "${NEW_FILESIZE}" ]; then
    echo -e "${BODY}"$(tail -${LAST_LINES} ${FILE_TO_WATCH}) | mail -s "${SUBJECT}" "${MAILTO}"
fi
0
yunzen