
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-tools
pacote?
Responder1
Você pode usarferramentas inotifydefinitivamente na linha de comando, por exemplo, assim:
inotifywait -r -m /dir/to/monitor/
-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, $FILE
na 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 md5sum
comando se torna:
md5sum /home/terdon/foo/*
Em outras palavras, ele é executado md5sum
em 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 $PWD
aqui, 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-tools
pacote para monitorar todas as alterações em uma pasta em tempo real. Por exemplo, ele contém a inotifywait
ferramenta 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 inotifywatch
ferramenta coleta estatísticas de uso do sistema de arquivos e gera contagens de cada inotify
evento.
Caso queira monitorar com outras ferramentas, você pode usar find
com o -mmin
parâ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