Script Bash detectando alterações em arquivos de um diretório

Script Bash detectando alterações em arquivos de um diretório

Estou tentando criar um script que detecte se algum dos arquivos de um diretório foi alterado em um intervalo de 2 segundos. O que tenho até agora é:

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

Isso gera apenas uma vez o valor "Idêntico", quero verificar cada arquivo e gerar "Idêntico" ou "Diferente" para cada arquivo.

Editar: Isso pode ser feito sem instalar oinotify-toolspacote?

Responder1

Você pode usarferramentas inotifydefinitivamente na linha de comando, por exemplo, assim:

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

Dehomem inotify, espere

-m,--monitor

Em vez de sair após receber um único evento, execute indefinidamente. O comportamento padrão é sair após a ocorrência do primeiro evento.

E aqui está um script que monitora continuamente, copiado do arquivo 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

Responder2

Como outros explicaram, usar inotifyé a melhor solução. Vou apenas explicar por que seu script falha. Primeiramente, não importa em que linguagem você esteja programando, sempre que tentar depurar algo, a primeira regra é "imprimir todas as variáveis":

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

Então, como você pode ver acima, $FILEna verdade é expandido para $PWD/*. Portanto, o loop só é executado uma vez nocorda /home/terdon/foo/*e não em cada um dos arquivos do diretório individualmente. Então, o md5sumcomando se torna:

md5sum /home/terdon/foo/*

Em outras palavras, ele é executado md5sumem todos os arquivos do diretório de destino de uma só vez e não em cada um deles.

O problema é que você está citando sua expansão glob e isso impede que ela seja expandida:

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

Enquantovariáveisdeveria quaseser sempre citado, os globs não deveriam, pois isso os transforma em strings em vez de globs.

O que você pretendia fazer é:

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

Porém, não há razão para usar $PWDaqui, não está acrescentando nada de útil. A linha acima é equivalente a:

for FILE in *; do

Além disso, evite usar letras MAIÚSCULAS para variáveis ​​de shell. Eles são usados ​​para variáveis ​​ambientais definidas pelo sistema e é melhor manter suas próprias variáveis ​​em letras minúsculas.

Com tudo isso em mente, aqui está uma versão funcional e aprimorada do seu 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

Responder3

Você pode usar o inotify-toolspacote para monitorar todas as alterações em uma pasta em tempo real. Por exemplo, ele contém a inotifywaitferramenta que você pode usar como:

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

Você pode usar sinalizadores para filtrar apenas determinados eventos ou determinados arquivos. A inotifywatchferramenta coleta estatísticas de uso do sistema de arquivos e gera contagens de cada inotifyevento.

Caso queira monitorar com outras ferramentas, você pode usar findcom o -mminparâmetro (minutos modificados). Como 2 segundos equivalem a 0,033 minutos, você poderia usar:

find . -type f -mmin 0.033

Responder4

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

informação relacionada