Script di Bash che rileva la modifica dei file da una directory


10

Sto cercando di creare uno script che rilevi se uno dei file in una directory è stato modificato in un intervallo di 2 secondi. Quello che ho finora è:

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

Questo produce solo una volta il valore "Identico", voglio che controlli ogni file e produca "Identico" o "Diverso" per ogni file.

Modifica : questo può essere fatto senza installare il inotify-toolspacchetto?

Risposte:


11

Come altri hanno spiegato, l'uso inotifyè la soluzione migliore. Spiegherò solo perché la tua sceneggiatura fallisce. Prima di tutto, indipendentemente dal linguaggio in cui stai programmando, ogni volta che provi a eseguire il debug di qualcosa, la prima regola è "stampa tutte le variabili":

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

Quindi, come puoi vedere sopra, in $FILErealtà è espanso a $PWD/*. Pertanto, il ciclo viene eseguito solo una volta sulla stringa /home/terdon/foo/* e non su ciascuno dei file nella directory singolarmente. Quindi, il md5sumcomando diventa:

md5sum /home/terdon/foo/*

In altre parole, viene eseguito md5sumsu tutti i file nella directory di destinazione contemporaneamente e non su ciascuno di essi.

Il problema è che stai citando l'espansione glob e che ne impedisce l'espansione:

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

Mentre le variabili dovrebbero quasi sempre essere citate , i globs non dovrebbero, dal momento che le trasformano in stringhe anziché globs.

Quello che intendevi fare è:

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

Tuttavia, non c'è motivo di utilizzare $PWDqui, non sta aggiungendo nulla di utile. La riga sopra è equivalente a:

for FILE in *; do

Inoltre, evitare di usare lettere maiuscole per le variabili shell. Questi vengono utilizzati per le variabili ambientali impostate dal sistema ed è meglio mantenere le proprie variabili in minuscolo.

Con tutto questo in mente, ecco una versione funzionante e migliorata del tuo script:

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

Mentre for FILE in "${PWD}"/*; dofunziona sullo stesso set in quanto for FILE in *; donon è esattamente equivalente perché quest'ultimo non include i nomi dei percorsi.
Lambert,

1
@Lambert true, ma qui non fa differenza poiché, per definizione, lo script verrà eseguito da $ PWD
terdon

Sarebbe una buona idea usare md5sum -- "$file"invece di md5sum "$file"gestire il caso in cui un file inizia con a -. Ovviamente dovresti anche fare in modo che la tua implementazione di md5sum supporti la --fine del delimitatore di opzioni.
Harold Fischer,

9

Puoi usare inotify-tools sicuramente dalla riga di comando, ad esempio in questo modo:

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

Da uomo inotifywait

-m, --monitor

Invece di uscire dopo aver ricevuto un singolo evento, eseguirlo a tempo indeterminato. Il comportamento predefinito è di uscire dopo il primo evento.

Ed ecco uno script che monitora continuamente, copiato dal file man di 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

È possibile utilizzare il inotify-toolspacchetto per monitorare tutte le modifiche in una cartella in tempo reale. Ad esempio, contiene lo inotifywaitstrumento, che è possibile utilizzare come:

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

È possibile utilizzare i flag per filtrare solo determinati eventi o determinati file. Lo inotifywatchstrumento raccoglie le statistiche sull'utilizzo del filesystem e genera i conteggi di ciascun inotifyevento.

Puoi trovare altri esempi qui per esempio.

Se si desidera monitorare con altri strumenti, è possibile utilizzare findcon il -mminparametro (minuti modificati). Poiché 2 secondi equivalgono a 0,033 minuti, è possibile utilizzare:

find . -type f -mmin 0.033

1

Se si desidera monitorare a intervalli di due secondi, è possibile circondare il controllo con:

while true
do
    <your steps>
    sleep 2
done

Mentre questo testerà sequenzialmente i file e attenderà 2 secondi per ogni file trovato, suggerisco di trasformare il tuo controllo in una funzione:

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

Quale può essere usato nel whileciclo:

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

Si prega di notare la e &commerciale per eseguire i controlli in background per eseguire i controlli dei file in parallelo. Si noti che ciò può influire sulle prestazioni a seconda del numero di file trovati nella directory.

Si noti inoltre che ho modificato le echorighe per includere il nome file ( "$@") per visualizzare quale file è identico / diverso.


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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.