Bash-Skript erkennt Änderungen in Dateien aus einem Verzeichnis

Bash-Skript erkennt Änderungen in Dateien aus einem Verzeichnis

Ich versuche, ein Skript zu erstellen, das erkennt, ob eine der Dateien in einem Verzeichnis innerhalb eines 2-Sekunden-Intervalls geändert wurde. Bisher habe ich Folgendes:

#!/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

Dies gibt nur einmal den Wert „Identisch“ aus, ich möchte, dass es jede Datei prüft und für jede Datei „Identisch“ oder „Unterschiedlich“ ausgibt.

Bearbeiten: Kann dies ohne die Installation derinotify-toolsPaket?

Antwort1

Sie könneninotify-toolsauf jeden Fall von der Kommandozeile aus, zB so:

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

AusMann inotifywait

-m,--monitor

Anstatt nach dem Empfang eines einzelnen Ereignisses zu beenden, führen Sie es auf unbestimmte Zeit aus. Das Standardverhalten besteht darin, nach dem Auftreten des ersten Ereignisses zu beenden.

Und hier ist ein Skript, das kontinuierlich überwacht, kopiert aus der Man-Datei von 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

Antwort2

Wie andere bereits erklärt haben, inotifyist die Verwendung die bessere Lösung. Ich erkläre nur, warum Ihr Skript fehlschlägt. Zunächst einmal gilt: Egal, in welcher Sprache Sie programmieren, wenn Sie versuchen, etwas zu debuggen, lautet die erste Regel „alle Variablen drucken“:

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

Wie Sie oben sehen können, $FILEwird tatsächlich erweitert auf $PWD/*. Daher wird die Schleife nur einmal auf derSchnur /home/terdon/foo/*und nicht auf jede einzelne Datei im Verzeichnis einzeln. Dann md5sumlautet der Befehl:

md5sum /home/terdon/foo/*

Mit anderen Worten, es wird md5sumauf allen Dateien im Zielverzeichnis gleichzeitig ausgeführt und nicht auf jeder einzelnen.

Das Problem besteht darin, dass Sie Ihre Glob-Erweiterung zitieren und dies verhindert, dass sie erweitert wird:

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

WährendVariablensollte fastimmer zitiert werden, Globs sollten dies nicht tun, da sie dadurch zu Strings statt zu Globs werden.

Sie wollten Folgendes tun:

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

Es gibt jedoch keinen Grund, es $PWDhier zu verwenden, da es nichts Nützliches hinzufügt. Die obige Zeile entspricht:

for FILE in *; do

Vermeiden Sie außerdem die Verwendung von GROSSBUCHSTABEN für Shellvariablen. Diese werden für die vom System festgelegten Umgebungsvariablen verwendet und es ist besser, Ihre eigenen Variablen in Kleinbuchstaben zu schreiben.

Vor diesem Hintergrund finden Sie hier eine funktionierende, verbesserte Version Ihres Skripts:

#!/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

Antwort3

Mit dem Paket können Sie inotify-toolsalle Änderungen in einem Ordner in Echtzeit überwachen. Es enthält beispielsweise das inotifywaitTool, das Sie wie folgt verwenden können:

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

Sie können Flags verwenden, um nur bestimmte Ereignisse oder bestimmte Dateien zu filtern. Das inotifywatchTool sammelt Statistiken zur Dateisystemnutzung und gibt die Anzahl der einzelnen inotifyEreignisse aus.

Wenn Sie mit anderen Tools überwachen möchten, können Sie findden -mminParameter (modifizierte Minuten) verwenden. Da 2 Sekunden 0,033 Minuten entsprechen, könnten Sie Folgendes verwenden:

find . -type f -mmin 0.033

Antwort4

#!/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//[^[:alnum:]]/}
      r=$(md5sum "$f2")
      if [ "$r" = "${!v}" ]; then
        echo "Identical $f2"
      else
        echo "Different $f2"
      fi
      eval "${v}=\$r"
    done <<< "$find"
  done
  sleep 2
done

verwandte Informationen