Come rilevare nuovi file in una cartella con uno script bash ? Vorrei elaborare i file non appena vengono creati nella cartella. È possibile farlo o devo programmare uno script con cron che controlli i nuovi file ogni minuto?
Come rilevare nuovi file in una cartella con uno script bash ? Vorrei elaborare i file non appena vengono creati nella cartella. È possibile farlo o devo programmare uno script con cron che controlli i nuovi file ogni minuto?
Risposte:
Dovresti prendere in considerazione l'utilizzo inotifywait, ad esempio:
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
In Ubuntu inotifywaitè fornito dal inotify-toolspacchetto. A partire dalla versione 3.13 (attualmente in Ubuntu 12.04) inotifywaitincluderà il nome file senza l'opzione -f. Potrebbe essere necessario forzare le versioni precedenti. Ciò che è importante notare è che l' -eopzione inotifywaitè il modo migliore per eseguire il filtro degli eventi. Inoltre, il readcomando può assegnare l'output posizionale in più variabili che è possibile scegliere di utilizzare o ignorare. Non è necessario utilizzare grep / sed / awk per preelaborare l'output.
inotifywaitera proprio quello che volevo.
The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.Quindi, non ti resta inotifywait -m /path -e create |che provare a modificare questa risposta.
fswatch. Non l'ho scritto, ma è open source e lo uso.
Preferisco incron, poiché è più facile da gestire. Essenzialmente è un servizio che sfrutta inotifye puoi configurare le configurazioni per agire in base alle operazioni di modifica dei file.
Ex:
<directory> <file change mask> <command or action> options
/var/www/html IN_CREATE /root/scripts/backup.sh
Puoi vedere un esempio completo qui: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/
Ho appena risolto questo problema e non ho riscontrato grossi problemi, a parte una piccola possibilità di perdere file tra i controlli.
while true
do
touch ./lastwatch
sleep 10
find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done
Se l'elaborazione dei file non richiede troppo tempo, non dovresti perdere nessun nuovo file. Potresti anche fare da sfondo alle attività ... Non è a prova di proiettile, ma serve ad alcuni scopi senza strumenti esterni come inotify.
inotifynon è disponibile. Aggiungerei -type fper filtrare solo i file. In caso contrario verrà restituita anche la cartella.
-f filenameopzione è fantastica. Quindi l'unica domanda rimasta è come farlo iniziare al riavvio. Lo userò con il mio impianto solare per fare in os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")modo che la creazione di questo file causi l'utilizzo del computer master espeake l'annuncio della bassa tensione. Mi invia già un'e-mail, ma poiché il mio sistema parla già l'ora nella parte superiore dell'ora, ha tutto il resto. askubuntu.com/questions/977613/…
Puoi usarlo watchnel tuo script
watch -n 0.1 ls <your_folder>
Monitora la tua cartella ed elenca tutto ciò che contiene ogni 0,1 secondi
Inconveniente
Non è in tempo reale, quindi se un file è stato creato ed eliminato in meno di 0,1 secondi, questo non funzionerebbe, watchsupporta solo minimo 0,1 secondi.
Suppongo che la cartella di destinazione (la chiamerò isemptysolo per comodità) sia vuota e stai aspettando che uno o più file vengano rilasciati lì.
Puoi usare il seguente comando:
ls -1A isempty | wc -l
solo per verificare se la cartella è ancora vuota, infatti restituirà uno 0 se non ci sono nuovi file (quindi la isemptycartella è ancora vuota) o, d'altra parte, restituirà un valore maggiore di 0 (in realtà il numero dei file attualmente nella cartella).
Detto questo, uno sciocco test if / then può rendere il resto del lavoro:
if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
Ovviamente la do_somethingfunzione dovrà manipolare i file all'interno della isemptycartella e quindi rimuoverli dalla cartella stessa dopo l'elaborazione.
L'aggiunta di una riga come la seguente nel crontab eseguirà il controllo una volta al minuto e, do_somethingnaturalmente , attiverà l' azione se la cartella non è vuota:
* * * * * if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
Se si desidera rilevare nuovi file, quindi elaborarli e alla fine eliminare i file proseguiti è possibile utilizzare systemd.path . Questo metodo si basa su inotify. C'è un'opzione DirectoryNotEmpty, quindi systemd può eseguire lo script sempre quando rileva qualsiasi file nella directory. Devi ricordare che funzionerà solo se puoi eliminare i file proceduti e lo script lascia vuota la directory.
Preparare innanzitutto il file mymonitor.service
[Unit]
Description=Start the script
[Service]
Type=oneshot
ExecStart=/path/to/your/script
quindi vai a mymonitor.path per definire il percorso
[Unit]
Description= Triggers the service
[Path]
DirectoryNotEmpty=/path/to/monitor
[Install]
WantedBy=multi-user.target
Se il nome del file .path è uguale al nome del servizio, non è necessario specificare il nome del servizio nel file .path.
Si basa sul monitoraggio dell'accesso ai file per i manichini
entrL'utilizzo entrè il nuovo modo per farlo (è multipiattaforma). Nota entrnon utilizza il polling, il che gli dà un enorme vantaggio rispetto a molte delle alternative.
Utilizza
kqueue(2)oinotify(7)per evitare il polling.entrè stato scritto per rendere il feedback rapido e i test automatizzati naturali e del tutto ordinari.
Su BSD utilizza pledge(2)
Puoi installarlo con
apt-get install entr
dnf install entr
È possibile tenere traccia di una directory per nuove aggiunte utilizzando
while $(true); do
# echo ./my_watch_dir | entr -dnr echo "Running trigger..."
echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;
Opzioni spiegate (dai documenti),
-dTieni traccia delle directory dei file regolari forniti come input e chiudi se viene aggiunto un nuovo file. Questa opzione consente inoltre di specificare esplicitamente le directory. File con nomi che iniziano con '.' sono ignorati.-nEsegui in modalità non interattiva. In questa modalità entr non tenta di leggere dal TTY né di modificarne le proprietà.-rRicarica un processo figlio persistente. Come per la modalità operativa standard, un'utilità che termina non viene più eseguita fino a quando non viene elaborato un file system o un evento della tastiera.SIGTERMviene utilizzato per terminare l'utilità prima che venga riavviata. Viene creato un gruppo di processi per impedire agli script della shell di mascherare i segnali.entrattende che l'utilità venga chiusa per assicurarsi che risorse come i socket siano state chiuse. Il controllo del TTY non trasferisce il processo figlio.
Bash non può farlo facilmente. Dovresti sostanzialmente ottenere un elenco di tutti i file nella cartella e periodicamente ottenere un nuovo elenco e confrontarli per vedere cosa è cambiato.
Quello che stai cercando si chiama inotify. È integrato nel kernel di Linux e puoi praticamente rimanere seduto lì in attesa che accada qualcosa a quel punto inotify ritorna e dice "hey, c'è un nuovo file chiamato foobar"
Per ottenere ciò che desideri dovresti passare a qualcosa come perl e usare Linux :: Inotify2 (probabilmente Python supporta anche inotify, ma io sono una persona perl).
Funziona su Cygwin e Linux. Alcune delle precedenti soluzioni che scrivono un file causeranno il crash del disco. Questa sceneggiatura non presenta questo 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
Di seguito è riportata una versione ridotta dell'esempio su StackOverflow che ho testato e incorporato in uno dei miei progetti che richiede il monitoraggio di directory specifiche.
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
}
Ecco un collegamento a uno script che utilizza una versione modificata di cui sopra per decrittografare automaticamente i file o le directory trovati nel suo punto di montaggio sshfs; il suddetto progetto.