ディレクトリからのファイルの変更を検出するBashスクリプト


10

2秒間隔でディレクトリ内のファイルが変更されたかどうかを検出するスクリプトを作成しようとしています。これまでのところ、

#!/bin/bash
for FILE in "${PWD}/*"
do
    SUM1="$(md5sum $FILE)"
    sleep 2
    SUM2="$(md5sum $FILE)"
    if [ "$SUM1" = "$SUM2" ];
    then
        echo "Identical"
    else
        echo "Different"
    fi
done

これにより、値「同一」が1回だけ出力されます。各ファイルをチェックして、各ファイルの「同一」または「異なる」を出力します。

編集:これはinotify-toolsパッケージをインストールせずに実行できますか?

回答:


11

他の人が説明したように、使用するのinotifyがより良い解決策です。スクリプトが失敗する理由を説明します。まず第一に、どの言語でプログラミングしていても、何かをデバッグしようとするときはいつでも、最初のルールは「すべての変数を出力する」ことです。

$ ls
file1  file2  file3
$ echo $PWD    
/home/terdon/foo
$ for FILE in "${PWD}/*"; do echo "$FILE"; done
/home/terdon/foo/*

したがって、上記のように、$FILE実際にはに展開され$PWD/*ます。したがって、ループは文字列に対して 1回だけ実行さ/home/terdon/foo/*れ、ディレクトリ内の各ファイルに対して個別に実行されることはありません。次に、md5sumコマンドは次のようになります。

md5sum /home/terdon/foo/*

つまり、md5sumターゲットディレクトリのすべてのファイルではなく、一度にすべてのファイルで実行されます。

問題は、グロブ拡張を引用していて、それが拡張されないようにすることです。

$ echo "*"
*
$ echo *
file1 file2 file3

一方で、変数はほとんど必要があります常に引用されているが、文字列の代わりの塊にそれらを作るために、グロブはいけません。

あなたがやろうとしていたことは:

for FILE in "${PWD}"/*; do ...

ただし、$PWDここで使用する理由はありません。便利なものは何も追加されていません。上記の行は次と同等です。

for FILE in *; do

また、シェル変数に大文字を使用しないでください。これらはシステム設定の環境変数に使用されます。独自の変数は小文字にしておくことをお勧めします。

これらすべてを念頭に置いて、スクリプトの機能する改良版を次に示します。

#!/bin/bash
for file in *
do
    sum1="$(md5sum "$file")"
    sleep 2
    sum2="$(md5sum "$file")"
    if [ "$sum1" = "$sum2" ];
    then
        echo "Identical"
    else
        echo "Different"
    fi
done

ただし、後者はパス名を含まないため、まったく同じではないためfor FILE in "${PWD}"/*; do、同じセットで動作しfor FILE in *; doます。
ランバート

1
@Lambertはtrueですが、定義により、スクリプトは$ PWDから実行されるため、ここでは違いはありません
terdon

で始まるファイルを処理するmd5sum -- "$file"代わりにを使用することをお勧めします。もちろん、md5sumの実装がオプション区切り文字の終わりをサポートするようにする必要もあります。md5sum "$file"---
ハロルドフィッシャー

9

コマンドラインからinotify-toolsを確実に使用できます。たとえば、次のようにします。

inotifywait -r  -m /dir/to/monitor/

man inotifywaitから

-m--monitor

単一のイベントを受け取った後に終了する代わりに、無期限に実行します。デフォルトの動作では、最初のイベントが発生した後に終了します。

そして、以下のmanファイルからコピーされた、継続的に監視するスクリプトがありますinotifywait

#!/bin/sh
while inotifywait -e modify /var/log/messages; do
  if tail -n1 /var/log/messages | grep apache; then
    kdialog --msgbox "Blah blah Apache"
  fi
done

5

inotify-toolsパッケージを使用して、フォルダー内のすべての変更をリアルタイムで監視できます。たとえば、次のinotifywaitように使用できるツールが含まれています。

> inotifywait /tmp
Setting up watches.
Watches established.
/tmp/ MODIFY test

フラグを使用して、特定のイベントのみまたは特定のファイルをフィルタリングできます。このinotifywatchツールは、ファイルシステムの使用統計を収集し、各inotifyイベントの数を出力します。

たとえば、ここでより多くの例を見つけることができます。

他のツールで監視する場合findは、-mminパラメーター(変更された分)を使用できます。2秒は0.033分と同じなので、次のように使用できます。

find . -type f -mmin 0.033

1

2秒間隔で監視する場合は、小切手を次のように囲みます。

while true
do
    <your steps>
    sleep 2
done

これはファイルを順番にテストし、ファイルが見つかるまで2秒間待機しますが、チェックを関数に変換することをお勧めします。

function _check_file()
{
    SUM1=$(md5sum "$@")
    sleep 2
    SUM2=$(md5sum "$@")
    if [ "$SUM1" == "$SUM2" ];
    then
        echo "$@: Identical"
    else
        echo "$@: Different"
    fi
}

whileループで使用できるもの:

while true
do
    for FILE in "${PWD}/"*
    do
        if [ -f "$FILE" ]
        then
            _check_file "$FILE" &
        fi
    done
    sleep 2
done

&ファイルのチェックを並行して実行するために、バックグラウンドでチェックを実行するためのアンパサンドに注意してください。これは、ディレクトリにあるファイルの数によっては、パフォーマンスに影響を与える可能性があることに注意してください。

またecho、ファイル名("$@")が含まれるように行を変更して、どのファイルが同一/異なるかを視覚化していることにも注意してください。


0
#!/bin/bash
# pass one or more folders as arguments
while true; do
  for f in "$@"; do
    date
    echo "Checking $f and subfolders"
    find=$(find "$f" -type f)
    while read -r f2; do
      # strip non-alphanumeric from filename for a variable var name
      v=${f2//[^[:alpha:]]/}
      r=$(md5sum "$f2")
      if [ "$r" = "${!v}" ]; then
        echo "Identical $f2"
      else
        echo "Different $f2"
      fi
      eval "${v}=\$r"
    done <<< "$find"
  done
  sleep 2
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.