ファイルの観察とチェックサムの比較

ファイルの観察とチェックサムの比較

スクリプトを使用してファイルを観察し、60秒ごとにファイルのmd5sumを比較して変更された場合は、画面に警告を印刷してみてください。

何をすべきかわかりません。それが私が持っているのですが、少し外れたようです。

#/bin/bash

watch=$@

if [ -z "$watch" ]
    then
        echo "No file specified, aborting"
        exit 
else
    echo "watching : $watch"
fi

while [ 1 ]; do
watch -n 60 -d md5sum $watch
done

私もこれを行いましたが、うまくいくようです(一種の)。ファイルが変更されたかどうかを通知しますが、watchコマンドを使用しません。ウォッチでこれを行う方法はありますか?

#/bin/bash

watch=$@

if [ -z "$watch" ]
   then
       echo "No file specified, aborting"
       exit 
else
    echo "watching : $watch"
fi

checksum1="empty"
while [ 1 ]; do

checksum2=$(md5sum $watch | md5sum | cut -d ' ' -f1)
if [ "$checksum2" != "$checksum1" ];
then
echo "Warning : $watch has been changed"
#mail -s "$watch has been changed" "[email protected]"
echo -e "\a"
fi
checksum1="$checksum2"
sleep 60
done

答え1

あなたははるかに良い状況にありますinotify、これはファイル監視という目的で作成されました。


編集する:リンクされた質問に対する回答をここにまとめます。

ファイルやディレクトリを監視する必要があるときはいつでも、inotifyはその操作に適したツールです。監視したいイベント(ファイルへのアクセス、変更、開く、閉じる、削除など)をinotifywaitに通知できます(man inotifywait詳細を見る)。

最初の方法は次のループです。

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

最大の欠点は、イベントを見逃すことができることです。より効率的なバージョンは次のとおりです。

inotifywait -mq --format '%e' /path/to/file |
while IFS= read -r events; do
  /path/to/script "$events"
done

この後者のバージョンでは、イベントを見逃すことはありません。パイプはイベントがキューに入っていることを確認します。ループが時間内に選択されていない場合は積み重ねられますが、欠落している項目はありません。


編集する:テキストファイルを追跡する場合は、強力なハッシュを使用してファイルを追跡するので、gitもお勧めします。以下はメインループのbash擬似コードですinotify

git status file     # Tells whether <file> was modified
if file was modified; then
    git commit -- file  # Add <file> to the repository
    keep only the last two versions of <file>
    print the warning message
fi

これをベースとして使用できます。たぶん、git出力を解析する必要があります。私はあなたに正しい方法を話すのに十分に使用していませんが、それがトリックを実行できるような直感があります;-)。

答え2

私はこの答えを嫌いますが、約15分間この答えで遊んだ後は、コマンドでそれを達成する方法がないと思います。watch(他の人は私が間違っていることを証明してください。)

問題は、watch独自のループで独自に実行され、シェルへのデータの供給を中断することなく、独自のエコーのみを提供することです。

watchrun がどのように動作するかによって、どのようなifor whilecheck ステートメントでもこれを使用すると、シェルが結果を返さないため、変更を評価する機会は提供されません。ループを手動で終了するまでこれを保持します。

2番目の例のように、独自のループを実行してmd5sumをチェックすることは、目的のタスクを実行するための最良の方法です。

たとえば、質問

echo `watch -d md5sum testfile.txt`

エコーは決して消えません。エコーが端末に到達する方法を見つけることができれば、それスクリプトを実行する答えです。

答え3

ファイルパラメータを提供し、md5sumを使用するというアイデアに従うこの粗雑なスクリプトを試してください。 md5sumが変更されるたびにタイムスタンプが表示された行が表示され、ログファイルが保存され、ctrl-cを押すと停止します。コンテンツwatch_and_notify.sh:

#!/bin/bash

logf="$1.log"

interval=2

first_run=

# temp files, current and last md5s for diff to compare
lm1="$(mktemp /tmp/lm1.$$.XXXX)"
lm2="$(mktemp /tmp/lm2.$$.XXXX)"

if [ -z "$1" ]; then
        echo "No file specified, aborting" >&2
        exit 1
fi

echo "Watching at ${interval}s intervals:   $1"

# loop forever until cancel this script
while true; do

    md5sum "$1" > $lm1

    # otherwise in the first iteration,
    # lm2 does not yet exist, so diff
    # will always unintentionally report
    # a difference when comparing existing
    # file with nonexisting file
    if [ -z "$first_run" ]; then
        cp -a $lm1 $lm2
        first_run=1
    fi

    # test ! to invert usual exit code
    if ! diff $lm2 $lm1; then
        echo -e "$(date +"%F %R")\tChange detected:\t$1" | tee -a "$logf"
    fi

    # rotate
    mv $lm1 $lm2

    sleep $interval

done

# when you ctrl-c it should garbage cleanup
trap "rm $lm1 $lm2; exit 1" SIGINT

はい

次の名前の空のテキストファイルを起動します。a.txt

$ touch a.txt

次のようにスクリプトを実行し、以下を確認してください。

$ ./watch_and_notify.sh a.txt
Watching at 2s intervals:       a.txt

2番目の端末では変更をテストします。

$ echo addition >> a.txt

最初の端末でスクリプトを実行すると、アップデートが表示されます。

Watching at 2s intervals:       a.txt

1c1
< d41d8cd98f00b204e9800998ecf8427e  a.txt
---
> 9913e6909c108b5c32c69280474b2b2a  a.txt
2015-09-29 15:56        Change detected:        a.txt

2番目の端末で別の変更を適用します。

$ echo anotherchange >> a.txt

その後、スクリプトを実行する最初の端末で出力が再度更新されます。

Watching at 2s intervals:       a.txt
1c1
< d41d8cd98f00b204e9800998ecf8427e  a.txt
---
> 9913e6909c108b5c32c69280474b2b2a  a.txt
2015-09-29 15:56        Change detected:        a.txt
1c1
< 9913e6909c108b5c32c69280474b2b2a  a.txt
---
> 5c1c20a75b9982128f8300a7940f9ce0  a.txt
2015-09-29 16:06        Change detected:        a.txt

あなたはやめましたctrl-c。コマンドプロンプトに戻ります。コンテンツを一覧表示し、ログがあることを確認します。

$ ls -lh
total 12K
-rw-r--r-- 1 meme meme  22 Sep 29 16:06 a.txt
-rw-r--r-- 1 meme meme  80 Sep 29 16:06 a.txt.log
-rwxrwxrwx 1 meme meme 775 Sep 29 15:26 watch_and_notify.sh

ログを見ると、変更の瞬間を記録するのと同じタイムスタンプ項目が表示されます。

$ cat a.txt.log
2015-09-29 15:56        Change detected:        a.txt
2015-09-29 16:06        Change detected:        a.txt

コードの説明

全体的な流れのほとんどはスクリプト内のコメントを見ると分かりますが、基本的にファイルに対してmd5sumコマンドを繰り返し実行しながら結果を保存して回転させ、プログラムが現在の結果を以前の繰り返し結果diffと比較するようにします(もしすべて)。レポート操作を実行します。この場合、これらのジョブはタイムスタンプとともに画面に出力され、ログに追加されます。ユーザーはctrl-cを使用してスクリプトを停止し、差が検出されたタイムスタンプの瞬間にログを残します。

スクリプト内で

lm1="$(mktemp /tmp/lm1.$$.XXXX)"
lm2="$(mktemp /tmp/lm2.$$.XXXX)"
  • lm1 と lm2 は、比較のために md5sum 出力を保存するために使用される一時ファイルであり、スクリプトの実行時にのみ生成されます。
  • あなたが言ったように、重要な方法は文字通りmd5sumを比較するので、そのために最初に保存する一時的な場所を定義します。
  • mktemp一意の一時ファイル名を作成するのに役立ちます。
  • $$現在のプロセスIDで、ランダム性を追加します。
  • XXXXX各文字を任意の英数字にmktemp置き換えるように指示します。X

したがって、実行時に /tmp に、定義したパターンで指定されたファイルが 1 つ以上含まれていることを確認できます。

$ ls -lh /tmp/lm*
-rw-r--r-- 1 meme meme 40 Sep 29 15:08 /tmp/lm2.8248.xGJTl

次に、whileループがあります。

# loop forever until cancel this script
while true; do

...

done

ほとんどのコードは大きなwhile <command>; do ... doneループにはめ込まれています。コマンド/条件はtrue常にtrueなので、このコードは停止するまで無期限に実行されますctrl-c

各ループ反復は、まず現在の反復のmd5sum結果を生成して保存します。

md5sum "$1" > $lm1
  • $1最初の位置パラメータを示します。この場合、実行すると次のようになりますwatch_and_notify.sh a.txt$1a.txt
  • > $lm1前に定義した一時ファイルへの出力の書き込み

初めて実行すると、以前の反復はありません。ただし、コマンドはdiff以前のmd5sum結果の変更を$lm2 比較する必要があるように配置されています$lm1。これは、最初の実行では常に誤って違いを示すため、最初の実行では特別な条件付き操作が必要です。最初の実行を認識できるように、whileループの前に定義された初期空の変数を作成します。

first_run=

次に、ループ内で次をテストします。

    if [ -z "$first_run" ]; then
        cp -a $lm1 $lm2
        first_run=1
    fi
  • -z0 値をテストします。最初の繰り返しの場合は、$ first_runは常に空なので、そのthenセクションに進んでください。
  • このthenセクションでは、「前の繰り返し」をコピーして「偽」にします。$lm1したがって、後でdiff最初の反復では、2つの同じファイルを比較し、違いは報告されません。
  • first_run=1これにより、次の反復ではif [ -z "$first_run" ]; thenゼロ$first_run値ではなくなり、このthen部分はトリガーされないため、この操作は最初の反復でのみ実行されます。

diff次に、前の反復のmd5sum結果(変数で参照されるファイルに保存されている)$lm2と現在の反復のmd5sum結果(変数で参照されるファイルに保存されている)とを比較する実際の条件があります。$lm1

if ! diff $lm2 $lm1; then
  • diff私たちはコマンドの終了コードに反応することに頼っています。
  • diff file1 file2同じ場合、通常は終了コード0が発生します。実行時にこれをテストすると、ゼロ$ diff a.txt a.txt; echo $?が表示されます。異なる場合、$ diff a.txt b.txt; echo $?たとえば、b.txt異なる結果があるでしょう。1
  • しかし、0bashはその意味が次のようtrue1なると思います。false
  • したがって、ファイルが同じ場合は次のように解釈され、セクションをトリガーする終了コード0を提供するif diff $lm2 $lm1; thenため、これを行うことはできません。difftruethen
  • 私たちは反対の行動を望み、同じなら何もせず、違うと何かをします。
  • !出力反転ヘルプ

したがって、変更をテストできます。

変更が発生した場合の対処方法は次のとおりです。

    echo -e "$(date +"%F %R")\tChange detected:\t$1" | tee -a "$logf"
  • echo-eレンダリングを\tタブとして使用
  • date +"%F %R"現在のタイムスタンプを指定された形式でレンダリングします(例:2015-09-29 15:56)。
  • |teeプログラムによるパイプ出力
  • tee発生した変更に関する出力メッセージを表示し、出力を保存できます。
  • -a保存方法をさらに設定してください。それ以外の場合は、結果があるたびに前の結果が上書きされます。

現在の繰り返し作業はほぼ完了している。diff比較と操作が完了した後、次の反復を準備するために、次の手順を実行します。

    mv $lm1 $lm2
  • mv$lm1に保存されている現在の繰り返しのmd5sum結果をからに移動するか、名前を変更します$lm2
  • したがって、diff $lm2 $lm1次の反復では、実際に前の反復のmd5sumを比較します。

最後のループの最後の行は、sleep句sleep $intervalです。

  • sleep$interval変数として提供される結果の遅延(秒)
  • $intervalファイルの先頭に設定された変数は次のとおりです。2
  • したがって、各反復は2秒間続きます。

    完璧

  • done最後に閉じるwhile ...;do ... doneループがあります。

関連情報