Script Bash detectando mudanças nos arquivos de um diretório

7

Eu estou tentando fazer um script que detecta se algum dos arquivos em um diretório foi alterado em um intervalo de 2 segundos. O que eu 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", eu quero verificar cada arquivo e saída "Idêntica" ou "Diferente" para cada arquivo.

EDIT: Isso pode ser feito sem instalar o pacote inotify-tools?

    
por dasj19 18.05.2016 / 10:59

4 respostas

9

Como outros explicaram, usar inotify é a melhor solução. Eu só vou explicar porque seu script falha. Primeiro de tudo, não importa em que idioma você está programando, sempre que você 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, $FILE está realmente expandido para $PWD/* . Portanto, o loop só é executado uma vez na string /home/terdon/foo/* e não em cada um dos arquivos no diretório individualmente. Então, o comando md5sum se torna:

md5sum /home/terdon/foo/*

Em outras palavras, ele executa md5sum em todos os arquivos no diretório de destino de uma vez e não em cada um deles.

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

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

Embora variáveis devam ser sempre citadas , as globs não deveriam transforma-os em cordas em vez de globs.

O que você pretendia fazer é:

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

No entanto, não há motivo para usar $PWD aqui, não está adicionando nada útil. A linha acima é equivalente a:

for FILE in *; do

Além disso, evite usar letras maiúsculas para variáveis do shell. Esses são usados para as 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 aprimorada e funcional 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
    
por 18.05.2016 / 12:26
6

Você pode usar inotify-tools definitivamente da linha de comando, por exemplo assim:

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

De man inotifywait

-m, --monitor

Instead of exiting after receiving a single event, execute indefinitely. The default behaviour is to exit after the first event occurs.

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
    
por 18.05.2016 / 11:18
5

Você pode usar o pacote inotify-tools para monitorar todas as alterações em uma pasta em tempo real. Por exemplo, ele contém a ferramenta inotifywait , 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 ferramenta inotifywatch coleta estatísticas de uso do sistema de arquivos e gera contagens de cada evento inotify .

Você pode encontrar mais exemplos aqui , por exemplo.

Se você quiser monitorar com outras ferramentas, use find com o parâmetro -mmin (minutos modificados). Como 2 segundos é como 0,033 minutos, você poderia usar:

find . -type f -mmin 0.033
    
por 18.05.2016 / 11:05
1

Se você quiser monitorar em um intervalo de dois segundos, você pode cercar sua seleção com:

while true
do
    <your steps>
    sleep 2
done

Embora isso teste sequencialmente os arquivos e espere 2 segundos para cada arquivo encontrado, sugiro que você o transforme em uma função:

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

Que pode ser usado no loop while :

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

Observe o & E comercial para executar as verificações em segundo plano para executar as verificações de arquivo em paralelo. Observe que isso pode afetar o desempenho, dependendo do número de arquivos encontrados no diretório.

Observe também que alterei as linhas echo para incluir o nome do arquivo ( "$@" ) para visualizar qual arquivo é considerado idêntico / diferente.

    
por 18.05.2016 / 12:53