Verzeichnisüberwachung

Di, 31. August 2021, Ralf Hersel

In der Kategorie 'Tipps und Tricks' habe ich heute ein praktisches Beispiel aus einem meiner aktuellen Projekte für euch am Start. In diesem Projekt geht es darum, eingescannte Rechnungsbelege über einen SFTP-Server an einen OCR-Service und die Buchhaltung-Anwendung zu übertragen. Konkret geht es darum, geänderte Dateien (die gescannten Rechnungen) auf einem Remote-Server zu überwachen.

Der Anwendungsfall lautet: Ihr habt einen Server auf dem Dinge passieren, und zwar in Form von sich ändernden Dateien. Diese möchtet ihr beobachten und die Änderungen in einer Datei zusammenfassen, um den Überblick zu behalten. Im Folgenden beschreibe ich, wie man das umsetzen kann.

Die Grundvoraussetzung ist, dass man einen SSH-Zugriff auf den Server hat. Dort kommt dann inotify für die Verzeichnisüberwachung zum Einsatz. Das zugehörige Paket heisst inotify-tools, welches zum Beispiel auf einem CentOS-Server mittels sudo yum install inotify-tools installiert werden kann. Im Paket sind zwei Werkzeuge enthalten:

  • inotifywait: auf Dateisystemereignisse warten und bei Erhalt eines Ereignisses handeln
  • inotifywatch: Sammelt Statistiken über die Dateisystemnutzung und gibt die Anzahl der konfigurierten Dateisystemereignisse aus.

Für den hier beschriebenen Anwendungsfall setze ich inotifywait ein. Das entsprechende Kommando lautet:

inotifywait -m -r -e create,delete,move \
--timefmt '%y.%m.%d - %H:%M:%S' --format '%T %w %e %f' \
/data/Test-Kreditoren /data/Test-Debitoren \
| xargs -I {} sed -i '1s|^|{}\n|' changes.txt

Der Parameter -m bewirkt, dass inotifywait kontinuierlich läuft, statt beim ersten Event die Arbeit abzubrechen. Mit dem Parameter -r werden auch Unterverzeichnisse überwacht. Hinter dem Paramter -e kann angegeben werden, auf welche Ereignisse (z.B.: create, delete, und viele andere) die Überwachung reagieren soll. Falls man in der Ausgabe einen Zeitstempel sehen möchte, kann dieser mit --timefmt definiert und bei --format verwendet werden '%T'. Als Nächstes gibt man an, welche Verzeichnisse beobachtet werden sollen.

Nun wird es spannend. Die Ausgabe soll in die Datei changes.txt geschrieben werden. Da das Ergebnis von inotifywait nicht direkt an den Stream Editor sed gepiped werden kann, muss man xargs als Brücke zwischen den beiden Befehlen verwenden. xargs -I {} nimmt die Ausgabe von inotifywait entgegen, welche bei sed mit {} weiterverwendet wird. Sed wird so verwendet, dass die Ausgabe von inotifywait immer als erste Zeile in die Datei changes.txt geschrieben wird (Parameter 1s). Dadurch stehen in changes.txt die aktuellsten Einträge immer oben und man spart sich das Hinunterscrollen in einer langen Liste. Hinter jeden Zeileninhalt {} wird mit \n ein Zeilenumbruch geschrieben. Übrigens sind die | bei sed keine Pipes, sondern alternative Delimiter, weil es ansonsten Probleme mit den / in den Dateipfaden gibt.

Der Inhalt der Datei sieht zum Beispiel so aus:

21.08.30 - 23:07:44 /data/Test-Kreditoren/ DELETE .e4defrag2_donor.tmp
21.08.30 - 23:07:44 /data/Test-Kreditoren/ CREATE .e4defrag2_donor.tmp
21.08.30 - 23:07:44 /data/Test-Kreditoren/Archiv/ DELETE .e4defrag2_donor.tmp
21.08.30 - 23:07:44 /data/Test-Kreditoren/Archiv/ CREATE .e4defrag2_donor.tmp
21.08.30 - 23:07:44 /data/Test-Kreditoren/Transfer/ DELETE .e4defrag2_donor.tmp
21.08.30 - 23:07:44 /data/Test-Kreditoren/Transfer/ CREATE .e4defrag2_donor.tmp
Change Log

Da der sed Befehl in dieser Form mindestens eine Zeile voraussetzt, steht in der untersten Zeile das Wort 'Change Log'.

Zwar kann man den Befehl direkt im SSH-Terminal ausführen oder als kleines Shell-Skript implementieren, sobald man die SSH-Session beendet, stoppt auch der inotifywait Befehl. Die Anforderung ist jedoch, dass die Überwachung auch dann weiterläuft, wenn man die Session verlassen hat. Dieses Problem kann man mit einem Terminal-Multiplexer lösen.

Mit dem Linux-Befehl screen kann man laufende Terminalanwendungen in den Hintergrund schieben und sie nach vorne holen, wenn sie wieder gebraucht werden. Screen unterstützt auch geteilte Bildschirmanzeigen und funktioniert über SSH-Verbindungen, auch nachdem die Verbindung getrennt und wieder hergestellt wurde. Und so geht es: in der SSH-Session ruft man den Befehl screen -dR auf. Der Parameter -dR führt dazu, dass eine laufende Sitzung erneut aufgerufen wird bzw. eine neue erstellt wird, falls es keine gibt. In der Session kann dann der inotifywait Befehl aufgerufen werden. Danach verlässt man die Screen-Sitzung mit der Tastenkombination Ctrl+a, d und verlässt auch die SSH-Sitzung. Beim nächsten Anmelden ruft man erneut screen -dR auf und sieht die immer noch laufende Screen-Session.

Quelle: https://www.mankier.com/1/inotifywatch