Como detectar novos arquivos em uma pasta com um script bash ? Gostaria de processar os arquivos assim que eles forem criados na pasta. Isso é possível ou preciso agendar um script com cron que verifique se há novos arquivos a cada minuto ou mais?
Como detectar novos arquivos em uma pasta com um script bash ? Gostaria de processar os arquivos assim que eles forem criados na pasta. Isso é possível ou preciso agendar um script com cron que verifique se há novos arquivos a cada minuto ou mais?
Respostas:
Você deve considerar o uso inotifywait
, como exemplo:
inotifywait -m /path -e create -e moved_to |
while read path action file; do
echo "The file '$file' appeared in directory '$path' via '$action'"
# do something with the file
done
No Ubuntu inotifywait
é fornecido pelo inotify-tools
pacote. A partir da versão 3.13 (atual no Ubuntu 12.04) inotifywait
incluirá o nome do arquivo sem a opção -f. Versões mais antigas podem precisar ser coagidas. O que é importante observar é que a -e
opção inotifywait
é a melhor maneira de fazer a filtragem de eventos. Além disso, seu read
comando pode atribuir a saída posicional em várias variáveis que você pode optar por usar ou ignorar. Não há necessidade de usar grep / sed / awk para pré-processar a saída.
inotifywait
era exatamente o que eu queria.
The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.
Então, você só precisa fazer inotifywait -m /path -e create |
isso, vou tentar editar esta resposta.
fswatch
. Eu não escrevi, mas é de código aberto e eu o uso.
Eu prefiro incron
, pois é mais fácil de gerenciar. Essencialmente, é um serviço que aproveita inotify
e você pode definir configurações para executar ações com base nas operações de alteração de arquivo.
Ex:
<directory> <file change mask> <command or action> options
/var/www/html IN_CREATE /root/scripts/backup.sh
Você pode ver um exemplo completo aqui: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/
Acabei de preparar isso e não vejo grandes problemas com isso, além de uma pequena chance de perder arquivos entre as verificações.
while true
do
touch ./lastwatch
sleep 10
find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done
Se o processamento do arquivo não demorar muito, você não deve perder nenhum novo arquivo. Você também pode ter as atividades em segundo plano ... Não é à prova de balas, mas serve a alguns propósitos sem ferramentas externas, como inotify.
inotify
não estiver disponível. Eu adicionaria -type f
para filtrar apenas os arquivos. Caso contrário, a pasta também será retornada.
-f filename
opção é ótima. Portanto, a única questão restante é como fazer isso iniciar na reinicialização. Vou usar isso com minha planta solar para os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")
que a criação desse arquivo faça com que o computador mestre use espeak
e anuncie a baixa tensão. Ele já me envia um e-mail, mas como meu sistema já fala as horas no início da hora, ele tem todo o resto. askubuntu.com/questions/977613/...
Você pode usar watch
no seu script
watch -n 0.1 ls <your_folder>
Monitora sua pasta e lista tudo a cada 0,1 segundos
Recua
Não é em tempo real; portanto, se um arquivo foi criado e excluído em menos de 0,1 segundo, isso não funcionaria, watch
apenas suportaria no mínimo 0,1 segundo.
Estou assumindo que a pasta de destino (vou chamá-la isempty
apenas por conveniência) está vazia e você está esperando um ou mais arquivos serem descartados lá.
Você pode usar o seguinte comando:
ls -1A isempty | wc -l
apenas para verificar se a pasta ainda está vazia, na verdade retornará um 0 se não houver um novo arquivo (portanto, a isempty
pasta ainda está vazia) ou, por outro lado, retornará um valor maior que 0 (na verdade, o número de arquivos atualmente na pasta).
Dito isso, um teste tolo de se / então pode fazer o resto do trabalho:
if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
Obviamente, a do_something
função terá que manipular o (s) arquivo (s) dentro da isempty
pasta e removê-lo (s) da própria pasta após o processamento.
Adicionar uma linha como a seguinte no seu crontab executará a verificação uma vez por minuto e acionará a do_something
ação se a pasta não estiver vazia, é claro:
* * * * * if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
Se você deseja detectar novos arquivos, processe-os e, no final, exclua os arquivos prosseguidos, você pode usar systemd.path . Este método baseia-se em inotify. Há uma opção DirectoryNotEmpty, para que o systemd possa executar seu script sempre que detectar qualquer arquivo no diretório. Você deve se lembrar que ele funcionará apenas se você puder excluir os arquivos prosseguidos e o script deixar o diretório vazio.
Primeiro prepare o arquivo mymonitor.service
[Unit]
Description=Start the script
[Service]
Type=oneshot
ExecStart=/path/to/your/script
Em seguida, vá para mymonitor.path para definir o caminho
[Unit]
Description= Triggers the service
[Path]
DirectoryNotEmpty=/path/to/monitor
[Install]
WantedBy=multi-user.target
Se o nome do arquivo .path for o mesmo que o nome do serviço, não será necessário especificar o nome do serviço no arquivo .path.
Baseia-se no monitoramento de acesso a arquivos para manequins
entr
Usar entr
é a nova maneira de fazer isso (é multiplataforma). A nota entr
não usa sondagem, o que oferece uma enorme vantagem sobre muitas das alternativas.
Usa
kqueue(2)
ouinotify(7)
para evitar pesquisas.entr
foi escrito para tornar o feedback rápido e os testes automatizados naturais e completamente comuns.
No BSD, ele usa pledge(2)
Você pode instalá-lo com
apt-get install entr
dnf install entr
Você pode rastrear um diretório para novas adições usando
while $(true); do
# echo ./my_watch_dir | entr -dnr echo "Running trigger..."
echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;
Opções explicadas (nos documentos),
-d
Acompanhe os diretórios dos arquivos regulares fornecidos como entrada e saia se um novo arquivo for adicionado. Esta opção também permite que os diretórios sejam especificados explicitamente. Arquivos com nomes começando com '.' são ignorados.-n
Execute no modo não interativo. Nesse modo, o entr não tenta ler o TTY ou alterar suas propriedades.-r
Recarregue um processo filho persistente. Como no modo de operação padrão, um utilitário que termina não é executado novamente até que um evento do sistema de arquivos ou do teclado seja processado.SIGTERM
é usado para finalizar o utilitário antes de ser reiniciado. Um grupo de processos é criado para impedir que scripts de shell ocultem sinais.entr
aguarda a saída do utilitário para garantir que recursos como soquetes foram fechados. O controle do TTY não é transferido para o processo filho.
O Bash não pode fazer isso facilmente. Você precisaria basicamente obter uma lista de todos os arquivos na pasta e periodicamente obter uma nova lista e compará-los para ver o que mudou.
O que você está procurando é chamado inotify. Ele está embutido no kernel do linux e você pode basicamente ficar sentado esperando que algo aconteça. Nesse momento, o inotify volta e diz 'ei, existe um novo arquivo chamado foobar'
Para realizar o que você deseja, você teria que mudar para algo como perl e usar Linux :: Inotify2 (o python provavelmente também suporta inotify, mas eu sou uma pessoa perl).
Isso funciona no cygwin e Linux. Algumas das soluções anteriores que escrevem um arquivo farão com que o disco seja danificado. Este scipt não tem esse problema:
SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
while [ $SIG = $SIG0 ] ; do
SIG=`ls -1 | md5sum | cut -c1-32`
sleep 10
done
SIG0=$SIG
ls -lrt | tail -n 1
done
Abaixo está uma versão resumida do exemplo no stackoverflow que eu testei e incorporei em um dos meus projetos que requer monitoramento de diretórios específicos.
Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
_added="$(grep -E '>' <<<"${@}")"
if [ "${#_added}" != "0" ]; then
mapfile -t _added_list <<<"${_added//> /}"
_let _index=0
until [ "${#_added_list[@]}" = "${_index}" ]; do
_path_to_check="${Var_dir}/${_added_list[${_index}]}"
if [ -f "${_path_to_check}" ]; then
echo "# File: ${_path_to_check}"
elif [ -d "${_path_to_check}" ]; then
echo "# Directory: ${_path_to_check}"
if [ -p "${_path_to_check}" ]; then
echo "# Pipe: ${_path_to_check}"
fi
let _index++
done
unset _index
fi
}
Func_watch_bulk_dir(){
_current_listing=""
while [ -d "${Var_dir}" ]; do
_new_listing="$(ls "${Var_dir}")"
_diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
if [ "${_diff_listing}" != "0" ]; then
Func_parse_diff "${_diff_listing}"
fi
_current_listing="${_new_listing}"
sleep ${Var_diff_sleep}
done
}
Aqui está um link para um script que usa uma versão modificada acima para descriptografar automaticamente arquivos ou diretórios encontrados em seu ponto de montagem sshfs; o projeto mencionado acima.