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

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.

MikeyB
fonte
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
user7119
fonte
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.

Andrew Ferrier
fonte
0

Existe um software apenas para esse fim, autoenv. Você pode querer verificar.

DukeLion
fonte
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).

clacke
fonte