Skript zum Überwachen des Ordners auf neue Dateien?

127

Wie erkenne ich neue Dateien in einem Ordner mit einem Skript? Ich möchte die Dateien bearbeiten, sobald sie im Ordner angelegt sind. Ist dies möglich oder muss ich ein Skript mit planen, das jede Minute nach neuen Dateien sucht?

ihatetoregister
quelle
1
Werden Sie nach der Verarbeitung Dateien aus dem Ordner entfernen?
ztank1013,

Antworten:

151

Sie sollten als inotifywaitBeispiel in Betracht ziehen :

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 inotifywaitist das inotify-toolsPaket vorgesehen. Ab Version 3.13 (aktuell in Ubuntu 12.04) inotifywaitwird der Dateiname ohne die Option -f angegeben. Ältere Versionen müssen möglicherweise erzwungen werden. Was wichtig ist, ist, dass die -eOption to inotifywaitdie beste Methode zum Filtern von Ereignissen ist. Außerdem kann Ihr readBefehl die Positionsausgabe mehreren Variablen zuweisen, die Sie verwenden oder ignorieren können. Es ist nicht erforderlich, grep / sed / awk zu verwenden, um die Ausgabe vorzuverarbeiten.

Enzotib
quelle
1
Toll! Das inotifywaitwar genau das, was ich wollte.
ihatetoregister
2
Ich möchte dies nur aktualisieren. Sie brauchen keine Awk, um dies zu erreichen. Sie können die Ereignisse mit '-e create' filtern und nur den Dateinamen abrufen, indem Sie '-f% f' ausführen oder den vollständigen Pfad mit '-f% w% f' angeben. Die erste Zeile des obigen Skripts lautet also: inotifywait -m / path -f% w% f -e create |
Lugoues
2
@ Lugoues und jetzt, wenn Sie versuchen, -f zu verwenden, erhalten Sie The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.Also, müssen Sie nur tun, inotifywait -m /path -e create |ich werde versuchen, diese Antwort zu bearbeiten.
Bruno Bronosky
1
Jetzt gibt es auch ein portables Tool namens fswatch. Ich habe es nicht geschrieben, aber es ist Open Source und ich benutze es.
1
@Wender inotfiywait gibt beim Auslösen 3 Informationen in einer einzelnen Zeile aus. Die eingebaute 'read'-Bash liest die Eingabezeile und weist jede der drei Informationen einer Variablen zu. Somit wird das erste Stück dem variablen Pfad zugewiesen, das zweite der Aktion und das dritte der Datei. Wenn diesen Variablen Werte zugewiesen wurden, können sie später verwendet werden (wie in der Echolinie). Weitere Informationen: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim
26

Ich bevorzuge incron, da es einfacher zu handhaben ist. Im Wesentlichen handelt es sich um einen Dienst, inotifymit dem Sie Konfigurationen einrichten können, um basierend auf Dateiänderungsvorgängen Maßnahmen zu ergreifen.

Ex:

<directory> <file change mask> <command or action>  options
/var/www/html IN_CREATE /root/scripts/backup.sh

Ein vollständiges Beispiel finden Sie hier: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/

rynop
quelle
24

Ich habe das gerade ausgedacht und sehe keine großen Probleme damit, abgesehen von einer winzigen Chance, dass Dateien zwischen Überprüfungen fehlen.

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

Wenn Ihre Dateiverarbeitung nicht zu lange dauert, sollten Sie keine neue Datei verpassen. Sie könnten auch Hintergrundinformationen zu den Aktivitäten anzeigen ... Es ist nicht kugelsicher, dient jedoch einigen Zwecken ohne externe Tools wie inotify.

Michael Sacchi
quelle
Guter Fang. Ich habe es ein wenig verbessert, um Leerzeichen in Dateinamen zu unterstützen.
Michael Sacchi
Absolut. Das ist der richtige Weg. Ich bin mir nicht sicher, warum ich diesen Weg gegangen bin, ich benutze -exec routinemäßig.
Michael Sacchi
Es ist nicht in Echtzeit. Echtzeit ist immer am besten
Farhan
3
Beste Lösung, wenn inotifynicht verfügbar. Ich würde nur hinzufügen -type f, um Dateien herauszufiltern. Andernfalls wird der Ordner ebenfalls zurückgegeben.
Xiao Peng - ZenUML.com
Ja - die -f filenameOption ist großartig. Dann bleibt nur noch die Frage, wie dies beim Neustart gestartet werden kann. Ich werde dies mit meiner Solaranlage verwenden, os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")damit der Mastercomputer beim Erstellen dieser Datei espeakdie Niederspannung verwendet und ankündigt. Es sendet mir bereits eine E-Mail, aber da mein System die Uhrzeit bereits zur vollen Stunde anzeigt, hat es den Rest. askubuntu.com/questions/977613/…
SDsolar 20.11.17
19

Sie können watchin Ihrem Skript verwenden

watch -n 0.1 ls <your_folder>

Überwacht Ihren Ordner und listet Sie alle 0,1 Sekunden auf

Nachteil

Ist nicht in Echtzeit, wenn also eine Datei in weniger als 0,1 Sekunden erstellt und gelöscht wurde, dann würde dies nicht funktionieren, watchunterstützt nur mindestens 0,1 Sekunden.

GypsyCosmonaut
quelle
Genau das wollte ich mir merken! Danke vielmals!!
Joabe Lucena
9

Ich gehe davon aus, dass der Zielordner (der Einfachheit halber nenne ich ihn isempty) leer ist und Sie darauf warten, dass eine oder mehrere Dateien dort abgelegt werden.

Sie können den folgenden Befehl verwenden:

ls -1A isempty | wc -l

Nur um zu überprüfen, ob der Ordner noch leer ist, wird eine 0 zurückgegeben, wenn keine neue Datei vorhanden ist (daher ist der isemptyOrdner noch leer), oder es wird ein Wert größer als 0 zurückgegeben (tatsächlich die Nummer) Dateien im Ordner).

Das sagte ein dummer Wenn / Dann-Test kann den Rest der Arbeit machen:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

Natürlich muss die do_somethingFunktion die Datei (en) innerhalb des isemptyOrdners manipulieren und sie dann nach der Verarbeitung aus dem Ordner selbst entfernen.

Wenn Sie eine Zeile wie die folgende in Ihre crontab einfügen, wird die Prüfung einmal pro Minute ausgeführt und die do_somethingAktion ausgelöst, wenn der Ordner natürlich nicht leer ist:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
ztank1013
quelle
Diese Lösung funktioniert für gemountete Remote-Dateisysteme. Entwickler von inotify-tools arbeiten an der Sicherung (oder waren Mitte 2014).
Rondo
3
Sie sollten niemals lsfür Skripte verwenden. Verwenden Sie findstattdessen oder einfaches Globbing
andsens
6

Wenn Sie neue Dateien erkennen möchten, verarbeiten Sie diese und löschen Sie am Ende die verarbeiteten Dateien. Verwenden Sie dazu die Datei systemd.path . Diese Methode basiert auf inotify. Es gibt eine Option DirectoryNotEmpty, damit systemd Ihr Skript immer dann ausführen kann, wenn Dateien im Verzeichnis erkannt werden. Sie müssen sich daran erinnern, dass es nur funktioniert, wenn Sie verarbeitete Dateien löschen können und das Skript das Verzeichnis leer lässt.

Bereiten Sie zuerst die Datei mymonitor.service vor

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

Als nächstes gehen Sie zu mymonitor.path, um den Pfad zu definieren

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

Wenn der Name der .path-Datei mit dem Namen des Dienstes identisch ist, muss der Dienstname nicht in der .path-Datei angegeben werden.

Es basiert auf der Überwachung des Dateizugriffs auf Dummies

Dawid Wolski
quelle
4

entr

Verwenden entrist der neue Weg, dies zu tun (es ist plattformübergreifend). Beachten Sie, entrdass Polling nicht verwendet wird, um einen großen Vorteil gegenüber vielen Alternativen zu erzielen.

Verwendet kqueue(2)oder inotify(7)um Umfragen zu vermeiden. entrwurde geschrieben, um schnelle Rückmeldungen und automatisierte Tests natürlich und völlig normal zu machen.

Auf BSD verwendet pledge(2)

Sie können es mit installieren

apt-get install entr
dnf install entr

Sie können ein Verzeichnis für neue Ergänzungen mit verfolgen

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

Optionen erklärt (aus den Dokumenten),

  • -d Verfolgen Sie die Verzeichnisse der regulären Dateien, die als Eingabe bereitgestellt werden, und beenden Sie sie, wenn eine neue Datei hinzugefügt wird. Mit dieser Option können auch Verzeichnisse explizit angegeben werden. Dateien mit Namen, die mit '.' Beginnen werden ignoriert.
  • -nIm nicht interaktiven Modus ausführen. In diesem Modus versucht entr nicht, aus dem TTY zu lesen oder seine Eigenschaften zu ändern.
  • -r Laden Sie einen persistenten untergeordneten Prozess neu. Wie bei der Standardbetriebsart wird ein Dienstprogramm, das beendet wird, erst dann erneut ausgeführt, wenn ein Dateisystem- oder Tastaturereignis verarbeitet wird. SIGTERMwird verwendet, um das Dienstprogramm vor dem Neustart zu beenden. Eine Prozessgruppe wird erstellt, um zu verhindern, dass Shell-Skripte Signale maskieren. entrWartet auf das Beenden des Dienstprogramms, um sicherzustellen, dass Ressourcen wie Sockets geschlossen wurden. Die Steuerung des TTY wird nicht auf den Kindprozess übertragen.
Evan Carroll
quelle
2

Bash kann das nicht einfach. Sie müssten im Grunde genommen eine Liste aller Dateien im Ordner erstellen, regelmäßig eine neue Liste erstellen und diese vergleichen, um festzustellen, was sich geändert hat.

Was Sie suchen, heißt inotify. Es ist in den Linux-Kernel integriert und Sie können im Grunde dort sitzen und warten, bis etwas passiert. Dann kommt inotify zurück und sagt: "Hey, es gibt eine neue Datei namens foobar."

Um das zu erreichen, was Sie wollen, müssen Sie zu etwas wie Perl wechseln und Linux :: Inotify2 verwenden (Python unterstützt wahrscheinlich auch Inotify, aber ich bin eine Perl-Person).

Patrick
quelle
0

Dies funktioniert unter Cygwin und Linux. Einige der vorherigen Lösungen, die eine Datei schreiben, führen zu einem Thrash der Festplatte. Dieses Skript hat dieses Problem nicht:

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
user1186515
quelle
0

Unten finden Sie eine gekürzte Version eines Beispiels für Stackoverflow , das ich getestet und in eines meiner Projekte integriert habe und das die Überwachung bestimmter Verzeichnisse erfordert.

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
}

Hier ist ein Link zu einem Skript , das eine geänderte Version von oben verwendet, um Dateien oder Verzeichnisse, die sich im sshfs-Mountpunkt befinden, automatisch zu entschlüsseln. das vorgenannte Projekt.

S0AndS0
quelle