Bash-Skript zur Erkennung von Änderungen in Dateien aus einem Verzeichnis

10

Ich versuche, ein Skript zu erstellen, das erkennt, ob eine der Dateien in einem Verzeichnis innerhalb von 2 Sekunden geändert wurde. Was ich bisher habe ist:

#!/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 jede Datei überprüft und für jede Datei "Identisch" oder "Unterschiedlich" ausgegeben wird.

Bearbeiten : Kann dies ohne Installation des inotify-toolsPakets erfolgen?

dasj19
quelle

Antworten:

11

Wie andere erklärt haben, inotifyist die Verwendung die bessere Lösung. Ich werde nur erklären, warum Ihr Skript fehlschlägt. Unabhängig davon, in welcher Sprache Sie programmieren, lautet die erste Regel "Drucken Sie alle Variablen", wenn Sie versuchen, etwas zu debuggen:

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

Also, wie Sie oben sehen können, $FILEwird tatsächlich auf erweitert $PWD/*. Daher wird die Schleife nur einmal für die Zeichenfolge /home/terdon/foo/* und nicht für jede einzelne Datei im Verzeichnis ausgeführt. Dann wird der md5sumBefehl:

md5sum /home/terdon/foo/*

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

Das Problem ist, dass Sie Ihre Glob-Erweiterung zitieren und dass sie nicht erweitert werden kann:

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

Während Variablen fast immer in Anführungszeichen gesetzt werden sollten, sollten Globs dies nicht tun, da sie dadurch zu Strings anstelle von Globs werden.

Was Sie vorhatten, ist:

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

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

for FILE in *; do

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

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
terdon
quelle
Arbeitet zwar for FILE in "${PWD}"/*; doam selben Set for FILE in *; do, ist aber nicht genau gleichwertig, da letzteres die Pfadnamen nicht enthält.
Lambert
1
@ Lambert wahr, aber es macht hier keinen Unterschied, da das Skript per Definition von $ PWD
terdon
Es wäre eine gute Idee zu verwenden , md5sum -- "$file"anstatt md5sum "$file"den Fall zu behandeln , wo eine Datei mit einem beginnt -. Natürlich sollten Sie auch dafür sorgen, dass Ihre Implementierung von md5sum das --Ende des Optionsbegrenzers unterstützt.
Harold Fischer
9

Sie können inotify-tools definitiv über die Befehlszeile verwenden, z. B.: So:

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

Vom Menschen inotifywait

-m, --monitor

Anstatt nach dem Empfang eines einzelnen Ereignisses zu beenden, führen Sie die Ausführung auf unbestimmte Zeit aus. Das Standardverhalten ist das Beenden nach dem ersten Ereignis.

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

Mit dem inotify-toolsPaket können Sie alle Änderungen in einem Ordner in Echtzeit überwachen. Zum Beispiel enthält es 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 inotifyEreignisse aus.

Weitere Beispiele finden Sie hier zum Beispiel.

Wenn Sie mit anderen Tools überwachen möchten, können Sie findmit dem -mminParameter (geänderte Minuten) verwenden. Da 2 Sekunden 0,033 Minuten entsprechen, können Sie Folgendes verwenden:

find . -type f -mmin 0.033
Labyrinthe
quelle
1

Wenn Sie im Abstand von zwei Sekunden überwachen möchten, können Sie Ihren Scheck umgeben mit:

while true
do
    <your steps>
    sleep 2
done

Während dies nacheinander nach Dateien testet und 2 Sekunden auf jede gefundene Datei wartet, schlage ich vor, Ihre Prüfung in eine Funktion umzuwandeln:

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

Welches kann in der whileSchleife verwendet werden:

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

Bitte beachten Sie das &kaufmännische Und, um die Überprüfungen im Hintergrund durchzuführen und die Dateiprüfungen parallel durchzuführen. Beachten Sie, dass dies abhängig von der Anzahl der im Verzeichnis gefundenen Dateien die Leistung beeinträchtigen kann.

Beachten Sie auch, dass ich die echoZeilen so geändert habe , dass sie den Dateinamen ( "$@") enthalten, um zu visualisieren, welche Datei identisch / unterschiedlich ist.

Lambert
quelle
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
dw1
quelle