Script Bash que detecta cambios en archivos de un directorio

Script Bash que detecta cambios en archivos de un directorio

Estoy intentando crear un script que detecte si alguno de los archivos de un directorio se modificó en un intervalo de 2 segundos. Lo que tengo hasta ahora es:

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

Esto genera solo una vez el valor "Idéntico", quiero que verifique cada archivo y genere "Idéntico" o "Diferente" para cada archivo.

Editar: ¿Se puede hacer esto sin instalar elinotify-tools¿paquete?

Respuesta1

Puedes usarherramientas-inotifydefinitivamente desde la línea de comando, por ejemplo, así:

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

Dehombre inotifywait

-m,--monitor

En lugar de salir después de recibir un solo evento, ejecútelo indefinidamente. El comportamiento predeterminado es salir después de que ocurra el primer evento.

Y aquí hay un script que monitorea continuamente, copiado del archivo man de 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

Respuesta2

Como otros han explicado, usar inotifyes la mejor solución. Simplemente explicaré por qué falla tu script. En primer lugar, no importa en qué lenguaje estés programando, cada vez que intentas depurar algo, la primera regla es "imprimir todas las variables":

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

Entonces, como puede ver arriba, $FILEen realidad se expande a $PWD/*. Por lo tanto, el bucle sólo se ejecuta una vez en elcadena /home/terdon/foo/*y no en cada uno de los archivos del directorio individualmente. Entonces, el md5sumcomando se convierte en:

md5sum /home/terdon/foo/*

En otras palabras, se ejecuta md5sumen todos los archivos del directorio de destino a la vez y no en cada uno de ellos.

El problema es que estás citando tu expansión global y eso impide que se expanda:

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

Mientrasvariablesdebería casisiempre ser citado, los globos no deberían hacerlo, ya que eso los convierte en cadenas en lugar de globos.

Lo que querías hacer es:

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

Sin embargo, no hay ninguna razón para usarlo $PWDaquí, no agrega nada útil. La línea de arriba es equivalente a:

for FILE in *; do

Además, evite el uso de letras MAYÚSCULAS para las variables del shell. Se utilizan para las variables ambientales establecidas por el sistema y es mejor mantener sus propias variables en minúsculas.

Con todo esto en mente, aquí tienes una versión funcional y mejorada de tu 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

Respuesta3

Puede utilizar el inotify-toolspaquete para monitorear todos los cambios en una carpeta en tiempo real. Por ejemplo, contiene la inotifywaitherramienta que podría utilizar como:

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

Puede utilizar indicadores para filtrar solo ciertos eventos o ciertos archivos. La inotifywatchherramienta recopila estadísticas de uso del sistema de archivos y genera recuentos de cada inotifyevento.

Si desea monitorear con otras herramientas, puede usar findel -mminparámetro (minutos modificados). Dado que 2 segundos son como 0,033 minutos, podrías usar:

find . -type f -mmin 0.033

Respuesta4

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

información relacionada