Inotifywait für eine große Anzahl von Dateien in einem Verzeichnis

7

Was ich tun möchte, ist, ein Verzeichnis (nicht rekursiv, nur eines) auf neu erstellte Dateien zu überwachen und diese Dateien während des Schreibens an eine einzelne große Datei anzuhängen.

Die Anzahl der Dateien, die geschrieben werden, ist riesig und kann bis zu 50.000 erreichen.

Mit benutze inotifywaitich das Verzeichnis wie folgt:

inotifywait -m -e create ~/folder | awk '($2=="CREATE"){print $3}' > ~/output.file

Ich speichere also Namen neuer Dateien, die in erstellt wurden, ~/output.fileund verwende dann eine for-Schleife

for FILE in `cat ~/output.file` 
do
    cat $FILE >> ~/test.out
done

Es funktioniert einwandfrei, wenn die Geschwindigkeit, mit der eine Datei geschrieben (erstellt) ~/folderwird, 1 Datei pro Sekunde entspricht.

Die Anforderungen sind jedoch groß und die Rate, mit der die Dateien erstellt werden, ist sehr hoch, beispielsweise 500 Dateien pro Minute (oder sogar mehr).

Ich habe die Anzahl der Dateien ~/foldernach Abschluss des Vorgangs überprüft , aber sie stimmen nicht mit der inotifywaitAusgabe überein . Es gibt einen Unterschied von etwa 10 bis 15 Dateien, variiert.

Auch die Schleife

for FILE in `cat ~/output.file`
do
done

verarbeitet nicht alle Dateien, ~/output.filewährend sie geschrieben werden.

Kann mir bitte jemand eine elegante Lösung für dieses Problem vorschlagen?

Rohitkulky
quelle

Antworten:

6

Gibt es einen bestimmten Grund, den Sie verwenden:

 | awk '($2=="CREATE"){print $3}' > ~/output.file

stattdessen inotifywaitOptionen wie --formatund --outfile?

Wenn ich renne:

inotifywait -m --format '%f' -e create /home/don/folder/ --outfile /home/don/output.file

dann einen anderen Tab öffnen, cdauf ~/folderund laufen:

time seq -w 00001 50000 | parallel touch {}

real    1m44.841s
user    3m22.042s
sys     1m34.001s

(so bekomme ich viel mehr als 500 Dateien pro Minute) Alles funktioniert gut und output.fileenthält alle 50000Dateinamen, die ich gerade erstellt habe.
Sobald der Vorgang das Schreiben der Dateien auf die Festplatte abgeschlossen hat, können Sie sie an Ihre anhängen test.out(vorausgesetzt, Sie befinden sich immer in ~/folder):

xargs < /home/don/output.file cat >> final.file

Oder verwenden readSie, wenn Sie Dateien beim Erstellen verarbeiten möchten. Also, während in ~/folderSie laufen können:

inotifywait -m --format '%f' -e create ~/folder | while read file; do cat -- "$file" >> ~/test.out; done

Beachten Sie, dass in inotifywaitstabil -mund -tkann nicht zusammen verwendet werden. Unterstützung für die Verwendung von beiden Switches wurde vor kurzem so hinzugefügt , wenn Sie bauen inotify-toolsaus den gitSie verwenden können , sollten monitormit timeout(festlegen , wie lange es für ein entsprechendes Ereignis warten muss erfolgen , bevor Verlassen). Ich habe die gitVersion auf meinem System getestet (beenden, wenn createinnerhalb von 2 Sekunden keine Ereignisse auftreten) und es funktioniert einwandfrei:

inotifywait -m -t 2 --format '%f' -e create ~/folder | while read file; do cat -- "$file" >> ~/test.out; done
don_crissti
quelle
Ich möchte die Dinge parallel machen, um Zeit zu sparen. Erstellen kleiner Dateien und Anhängen dieser Dateien beim Erstellen. Awk filtert also die erstellten Dateien aus der Gesamtliste, die inotiify generiert.
Rohitkulky
Hey don, das funktioniert gut! Ich war früher darauf gestoßen, konnte aber die Dinge irgendwie nicht zum Laufen bringen. Vielen Dank! :)
Rohitkulky
Sie können diesen Kommentar der Klarheit halber in die Antwort einfügen, um anderer willen! :)
Rohitkulky
Es tut mir leid, dies zu spät zu erwähnen. Das obige Skript funktioniert einwandfrei, wie ich bereits sagte. Sobald der Dateierstellungsprozess im Verzeichnis abgeschlossen ist, wird der Prozess auf inotifywaitunbestimmte Zeit ausgeführt, sodass ich den Prozess manuell beenden muss. Gibt es eine Möglichkeit, dies elegant zu tun? Die --timeoutOption wartet nur auf das erste Ereignis und wird dann beendet. Vielen Dank!
Rohitkulky
@rohitvk - Sie können nicht verwenden monitorund timeoutzusammen mit der aktuellen Version müssen Sie die gitVersion installieren . Antwort aktualisiert.
don_crissti
0

Eine Möglichkeit besteht darin, ein kleines Programm zu erstellen, mit dem die verarbeiteten Dateien nach der Verarbeitung aus dem Verzeichnis in ein anderes verschoben werden. Starten Sie einfach den Scan des Verzeichnisses neu, nachdem Sie fertig sind. Ruhen Sie vor dem erneuten Scannen eine angemessene Zeit lang, wenn keine Dateien vorhanden sind, und tun Sie dies für die Dauer der Dateierzeugung (der Vorgang zum Generieren der Dateien scheint nur bis zu 100 Minuten oder so zu laufen).

Wenn Sie die Dateien nicht aus dem Verzeichnis verschieben können, besteht ein anderer Ansatz darin, irgendwo in der Vergangenheit mit einem Datums- / Zeitstempel-DTS zu beginnen. Suchen Sie dann alle Dateien, die neuer als DTS sind, verarbeiten Sie sie und aktualisieren Sie DTS, wenn der Zeitstempel der Datei neuer als DTS ist. Wiederholen Sie diesen Vorgang wie bei der obigen Lösung. Wenn die Granularität Ihrer Zeitstempel verhindert, dass zwei Dateien dieselbe haben, können Sie einfach nach Dateien suchen, die neuer als DTS sind. Wenn nicht, müssen Sie nach Dateien suchen, die nicht älter als DTS sind, und eine Liste der Dateien mit dem DTS führen, die Sie beim nächsten Lauf verwenden möchten, und diese beim nächsten Lauf herausfiltern.

Anthon
quelle