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-tools
pacchetto. A partire dalla versione 3.13 (attualmente in Ubuntu 12.04) inotifywait
includerà il nome file senza l'opzione -f. Potrebbe essere necessario forzare le versioni precedenti. Ciò che è importante notare è che l' -e
opzione inotifywait
è il modo migliore per eseguire il filtro degli eventi. Inoltre, il read
comando 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.
inotifywait
era 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 inotify
e 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.
inotify
non è disponibile. Aggiungerei -type f
per filtrare solo i file. In caso contrario verrà restituita anche la cartella.
-f filename
opzione è 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 espeak
e 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 watch
nel 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, watch
supporta solo minimo 0,1 secondi.
Suppongo che la cartella di destinazione (la chiamerò isempty
solo 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 isempty
cartella è 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_something
funzione dovrà manipolare i file all'interno della isempty
cartella 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_something
naturalmente , 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
entr
L'utilizzo entr
è il nuovo modo per farlo (è multipiattaforma). Nota entr
non 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),
-d
Tieni 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.-n
Esegui in modalità non interattiva. In questa modalità entr non tenta di leggere dal TTY né di modificarne le proprietà.-r
Ricarica 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.SIGTERM
viene 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.entr
attende 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.