Come eseguire automaticamente uno script quando il contenuto di una directory cambia in Linux?


17

Voglio eseguire automaticamente uno script ogni volta che nuovi file vengono copiati in una directory specifica. In altre parole, c'è un modo in Linux di "guardare" una directory per le modifiche e quindi eseguire qualcosa in risposta alla modifica?


Questa discussione si è svolta su ogni sito StackExchange;) vedere superuser.com/questions/181517/... stackoverflow.com/questions/4380527/... ecc
masterxilo

Risposte:


17

Se si ha la fortuna di essere su una distribuzione basata su Debian, apt-get install dnotify. Altre distribuzioni probabilmente hanno qualcosa di simile: cerca il dnotifynome.

dnotify è un semplice programma basato sull'API dnotify del kernel 2.4.19 + di Linux. dnotify può eseguire un comando specificato ogni volta che cambia il contenuto di una directory specifica. Viene eseguito dalla riga di comando e accetta due argomenti: una o più directory da monitorare e un comando da eseguire ogni volta che una directory è cambiata. Le opzioni controllano quali eventi attivare: quando un file è stato letto nella directory, quando ne è stato creato uno, eliminato e così via.

Se vuoi gestirlo nel tuo programma, dnotify è anche l'API che vuoi usare.


4
@MikeB, dopo che Google lo ha suggerito, ho finito per usare invece inotify, che apparentemente lo supera. Grazie per avermi indicato la giusta direzione. apt-get install inotify-tools
GeneQ

7
@GeneQ, inotify ha sostituito dnotify.
David,

1
Allo stesso modo su Gentoo:emerge inotify-tools
James Sneeringer il

Sì, stavo per dire che il kernel 2.4.19 è un po 'antico ;-) inotify è la strada da percorrere.
David Z,

Oh sì ... ho dimenticato quale era più recente :)
MikeyB,

12

Puoi eseguire uno script con gli strumenti inotify, qualcosa del genere. Controllerà la directory per le modifiche ai file modificati, nuovi file e file eliminati, quindi eseguirà lo script.

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

Basta considerare che se la directory di origine cambia mentre viene copiata, inotifywait NON la vedrà e tali modifiche non verranno copiate fino a quando non saranno state apportate ulteriori modifiche al termine della copia. Probabilmente non è un problema però.
Raúl Salinas-Monteagudo,

Come puoi eseguirlo in modalità demone?
Chris F,

4

incron è fondamentalmente quello che vuoi, penso. Usa inotify come meccanismo di notifica (che, come altri hanno sottolineato, sostituisce dnotify), ma non richiede uno script che viene eseguito continuamente, usando inotifywait o simili (sebbene, ovviamente, il demone incron sia sempre in esecuzione). I "crontab" a livello di sistema e i "crontab" dell'utente sono supportati in modo simile al cron standard, ma anziché specificare i tempi come trigger, inotificare eventi e vengono utilizzati i nomi di file / directory.

incron è confezionato per molte distribuzioni, tra cui Ubuntu e Debian, credo.


0

C'è un software esclusivamente per questo scopo, autoenv Potresti volerlo controllare.


0

entr è lo strumento di notifica file più semplice e compostabile che abbia mai visto. Il suo utilizzo è ottimizzato per la visione di file piuttosto che di directory, ma può anche risolvere il tuo caso.

Per rilevare e agire sul file aggiunto, combinalo con altri strumenti come ad es make. entrnon invia il nome o qualcosa del genere, esegue semplicemente ciò che gli hai detto di eseguire.

Per verificare la presenza di file aggiunti in una directory:

## 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 vuoi agire anche quando cambia un file esistente:

## 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

... ed è qui che il meccanismo del ciclo risulta utile, poiché l' findespressione verrà eseguita nuovamente se viene aggiunto un file.

Se vuoi una migliore gestione degli errori e vuoi assicurarti che le cose vengano eseguite solo una volta per file aggiunto / rimosso, le cose diventano un po 'eccentriche, ma per questi semplici casi è geniale.


EDIT: Se vuoi farlo a livello di sistema, qualcosa come incron , aggiungi lo script al tuo gestore dei processi preferito (come s6 , runit , systemd o sysvinit e salta il loop:

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

La execsostituzione di processo e ( <(...)) sono importanti quando si esegue da un gestore di processo, per gestire correttamente la segnalazione (cioè per togliere la shell).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.