Bestimmen Sie, ob die Datei gerade beschrieben wird?

25

Ich muss einen automatisierten Prozess (über ein 1-minütiges Cron-Skript) bereitstellen, der nach TAR-Dateien in einem bestimmten Verzeichnis sucht. Wenn eine TAR-Datei gefunden wird, wird sie an der entsprechenden Stelle nicht geteert und dann die TAR-Datei gelöscht.

Die tar-Dateien werden automatisch über SSH von einem anderen Server auf diesen Server kopiert. In einigen Fällen sind die TAR-Dateien extrem groß und enthalten viele Dateien.

Das erwartete Problem: Wenn das Kopieren der TAR-Datei auf den Server länger als 1 Minute dauert und das Cron-Skript einmal pro Minute ausgeführt wird, wird die Datei .tar.gz angezeigt und versucht, dies zu tun Entpacken Sie es, obwohl die TAR-Datei noch geschrieben wird.

Gibt es eine Möglichkeit (über Bash-Befehle) zu testen, ob eine Datei gerade geschrieben wird oder ob es sich nur um eine Teildatei usw. handelt?

Als Alternative habe ich mir überlegt, die Datei als andere Dateierweiterung (wie .tar.gz.part) zu kopieren und .tar.gznach Abschluss der Übertragung in umzubenennen. Aber ich dachte, ich würde versuchen herauszufinden, ob es einfach eine Möglichkeit gibt, festzustellen, ob die Datei in der Befehlszeile vollständig ist ... Irgendwelche Hinweise?

Jake Wilson
quelle
2
Wie genau wird die Datei übertragen? Zum Beispiel rsyncverwendet einen temporären Dateinamen während der Übertragung (Standard), und nur , nachdem die Datei vollständig übertragen wird, benennt es um die tatsächlichen Dateinamen.
Piskvor

Antworten:

12

Sie sind auf dem richtigen Weg, das Umbenennen der Datei ist eine atomare Operation, daher ist das Umbenennen nach dem Hochladen einfach, elegant und nicht fehleranfällig. Ein anderer Ansatz, den ich mir vorstellen kann, besteht darin, lsof | grep filename.tar.gzzu überprüfen, ob auf die Datei von einem anderen Prozess zugegriffen wird.

Alex
quelle
7
( lsof filename.tar.gzist effizienter und genauer als lsof | grep filename.tar.gz)
Rich
Übrigens
14

Am besten stellen Sie lsoffest, ob eine Datei von einem der folgenden Prozesse geöffnet wurde:

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog

Man kann nicht leicht sagen, ob es gerade geschrieben wird, aber wenn es geschrieben wird, MUSS es offen sein.


Bearbeiten: Lassen Sie uns das eigentliche Problem hier lösen, anstatt zu versuchen, die vorgeschlagene Lösung zu implementieren!

Verwenden Sie rsync, um die Datei zu übertragen:

  rsync -e ssh remote:big.tar.gz .

Auf diese Weise wird die Datei nicht über die vorhandene kopiert, sondern in eine temporäre Datei ( .big.tar.gz.XXXXXX) kopiert, bis die Übertragung abgeschlossen ist, und dann an ihren Platz verschoben.

MikeyB
quelle
6

Ein bisschen alt, aber die meisten Antworten verfehlen den Punkt der Frage völlig:

Aber ich dachte mir, ich würde versuchen herauszufinden, ob es einfach eine Möglichkeit gibt, zuerst festzustellen, ob die Datei in der Befehlszeile vollständig ist ...

Im Allgemeinen gibt es nicht. Sie haben einfach nicht genug Informationen, um das festzustellen.

Das Feststellen, dass die Datei geschlossen ist, ist nicht dasselbe wie das Feststellen, ob die Datei vollständig ist . Beispielsweise wird eine Datei "geschlossen", wenn die Verbindung während der Übertragung unterbrochen wird.

Nur die Antwort von @ Alex stimmte. Und selbst er verliebte sich in lsofetwas.

Um festzustellen, ob die Datei vollständig übertragen wurde, sind weitere Daten erforderlich. Sowie:

Als Alternative habe ich mir überlegt, die Datei als andere Dateierweiterung (wie .tar.gz.part) zu kopieren und .tar.gznach Abschluss der Übertragung in umzubenennen.

Auf diese Weise können Sie problemlos mitteilen, dass die Datei vollständig und erfolgreich übertragen wurde. Sie können auch Dateien von einem Verzeichnis in ein anderes verschieben, solange Sie sich im selben Dateisystem befinden. Oder lassen Sie den Absender eine leere filename.doneDatei senden , um die Fertigstellung zu signalisieren.

Alle Methoden müssen sich jedoch darauf verlassen, dass der Absender signalisiert, dass die Übertragung erfolgreich abgeschlossen wurde. Weil nur der Absender diese Informationen hat.

Einige Dateiformate (z. B. PDF-Dateien) enthalten Daten, anhand derer Sie feststellen können, ob die Datei vollständig ist. Sie müssen jedoch so ziemlich die gesamte Datei öffnen und lesen, um dies herauszufinden.

lsofwird Ihnen nur mitteilen, dass die Datei nicht mehr geöffnet ist - es wird Ihnen nicht mitgeteilt, warum sie nicht mehr geöffnet ist. Sie erfahren auch nicht, wie groß die Datei sein soll.

Andrew Henle
quelle
1
Ich kann das nicht genug unterstützen. Gute Arbeit bei der Lösung des XY-Problems.
Beefster
5

Am besten verwenden Sie dazu incron ("inotify cron system"). Sie können eine Inotify- Überwachung für ein Verzeichnis festlegen , die Sie dann über Dateivorgänge benachrichtigt. In diesem Fall sollten Sie das Verzeichnis auf close_write überwachen. Auf diese Weise können Sie Ihren Befehl ausführen, sobald die Datei nach einem Schreibvorgang geschlossen wurde.

Kyle
quelle
2

Anscheinend kann lsof erkennen, in welchem ​​Modus eine Datei geöffnet ist:

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

Sehen Sie, wo steht 1w? Das bedeutet, dass die Dateideskriptornummer 1 und der Modus w oder write ist.

Kevin Baragona
quelle
Das FDFeld zeigt 3rmir, wann die Datei zum Lesen geöffnet ist.
Sopalajo de Arrierez
0

Mit inotifywaitkönnen Sie das erreichen, wonach Sie suchen - Sie können warten, bis ein Dateischreibvorgang abgeschlossen ist, bevor Sie einen Befehl ausführen.

Der folgende Befehl überwacht kontinuierlich einen Ordner nach neuen Dateien und führt den Befehl in der Schleife aus, wenn das Schreiben in die Datei abgeschlossen ist.

WATCH_DIR=/directory/to/monitor
DEST_DIR=/x/y/z

/usr/bin/inotifywait --recursive --monitor --quiet -e moved_to -e close_write --format '%w%f' "$WATCH_DIR" | while read -r INPUT_FILE; do

mv "$0" "$DEST_DIR"

done

Weitere Konfigurationsoptionen finden Sie unter https://linux.die.net/man/1/inotifywatch

teeedubb
quelle