Como executar automaticamente um script quando o conteúdo de um diretório é alterado no Linux?


17

Quero executar automaticamente um script sempre que novos arquivos são copiados para um diretório específico. Em outras palavras, existe uma maneira no Linux de "observar" um diretório para alterações e executar algo em resposta à mudança?


Esta discussão foi realizada em cada local Stackexchange;) ver superuser.com/questions/181517/... stackoverflow.com/questions/4380527/... etc.
masterxilo

Respostas:


17

Se você tiver sorte o suficiente para estar em uma distribuição baseada no debian apt-get install dnotify,. Outras distribuições provavelmente têm algo parecido - procure o dnotifynome.

O dnotify é um programa simples baseado na API do dnotify do kernel 2.4.19 + do Linux. O dnotify pode executar um comando especificado sempre que o conteúdo de um diretório específico for alterado. É executado a partir da linha de comando e recebe dois argumentos: um ou mais diretórios para monitorar e um comando para executar sempre que um diretório é alterado. As opções controlam em quais eventos disparar: quando um arquivo foi lido no diretório, quando um foi criado, excluído e assim por diante.

Se você quiser lidar com isso dentro do seu próprio programa, dnotify também é a API que você deseja usar.


4
@ MikeB, depois que o Google notificou você sugeriu, acabei usando o inotify, o que aparentemente a supera. Obrigado por me indicar a direção certa. apt-get install inotify-tools
GeneQ 5/08/09

7
@GeneQ, inotify substituiu dnotify.
David

1
Da mesma forma no Gentoo:emerge inotify-tools
James Sneeringer

Sim, eu ia dizer, o kernel 2.4.19 é meio antigo ;-) inotify é o caminho a percorrer.
David Z

Oh yeah ... eu esqueci que era mais recente :)
MikeyB

12

Você pode executar um script com as ferramentas inotify, algo como isto. Ele observará o diretório quanto a alterações nos arquivos modificados, novos e excluídos, e executará o script.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done

Apenas leve em consideração que, se o diretório de origem for alterado enquanto estiver sendo copiado, o inotifywait NÃO o verá e essas alterações não serão copiadas até que outras alterações sejam feitas depois que a cópia terminar. Provavelmente não é um problema.
Raúl Salinas-Monteagudo

Como você pode executar isso no modo daemon?
Chris F

4

incron é basicamente o que você quer, eu acho. Ele usa inotify como mecanismo de notificação (que, como outros já apontaram, substitui o dnotify), mas não requer um script que seja executado continuamente, usando inotifywait ou similar (embora, obviamente, o daemon incron esteja em execução o tempo todo). 'Crontabs' em todo o sistema e 'crontabs' do usuário são suportados de maneira semelhante ao cron padrão, mas, em vez de especificar horários como acionadores, são utilizados eventos inotify e nomes de arquivos / diretório.

O incron é empacotado para muitas distribuições, incluindo Ubuntu e Debian, acredito.



0

entr é a ferramenta de notificação de arquivos mais simples e mais fácil de compor que já vi. Seu uso é otimizado para assistir arquivos, e não diretórios, mas também pode resolver o seu caso.

Para detectar e atuar no arquivo adicionado, combine-o com outras ferramentas, como por exemplo make. entrnão envia o nome ou algo assim, simplesmente executa o que você pediu para executar.

Para verificar se há arquivos adicionados em um diretório:

## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done

Se você também deseja agir quando um arquivo existente é alterado:

## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done

... e é aí que o mecanismo de loop é útil, pois a findexpressão será executada novamente se um arquivo for adicionado.

Se você deseja um melhor tratamento de erros e deseja garantir que as coisas sejam executadas apenas uma vez por arquivo adicionado / removido, as coisas ficam um pouco peculiares, mas, para esses casos simples, é brilhante.


EDIT: Se você quiser fazer isso no nível do sistema, algo como incron , basta adicionar o script ao seu gerenciador de processos favorito (como s6 , runit , systemd ou sysvinit e pular o loop:

#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)

A execsubstituição e o processo ( <(...)) são importantes ao executar a partir de um gerenciador de processos, para lidar com a sinalização corretamente (ou seja, para tirar o shell do caminho).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.