GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Datei verschieben, aber nur wenn sie geschlossen ist

Aus dem lsof Manpage

Lsof gibt eine Eins (1) zurück, wenn ein Fehler erkannt wurde, einschließlich des Fehlers beim Auffinden von Befehlsnamen, Dateinamen, Internetadressen oder -dateien, Anmeldenamen, NFS-Dateien, PIDs, PGIDs oder UIDs, um deren Auflistung er gebeten wurde. Wenn die Option -V angegeben ist, zeigt lsof die Suchelemente an, die nicht aufgelistet werden konnten.

Das würde also darauf hindeuten, dass Ihr lsof failed for some other reason Klausel würde niemals ausgeführt werden.

Haben Sie versucht, die Datei einfach zu verschieben, während Ihr externer Prozess sie noch geöffnet hat? Wenn sich das Zielverzeichnis auf demselben Dateisystem befindet, sollte es keine Probleme geben, es sei denn, Sie müssen von einem dritten Prozess unter dem ursprünglichen Pfad darauf zugreifen, da der zugrunde liegende Inode derselbe bleibt. Ansonsten denke ich mv wird sowieso scheitern.

Wenn Sie wirklich warten müssen, bis Ihr externer Prozess mit der Datei fertig ist, verwenden Sie besser einen Befehl, der blockiert, anstatt wiederholt abzufragen. Unter Linux können Sie inotifywait verwenden dafür. Beispiel:

 inotifywait -e close_write /path/to/file

Wenn Sie lsof verwenden müssen (vielleicht für die Portabilität), könnten Sie so etwas versuchen:

until err_str=$(lsof /path/to/file 2>&1 >/dev/null); do
  if [ -n "$err_str" ]; then
    # lsof printed an error string, file may or may not be open
    echo "lsof: $err_str" >&2

    # tricky to decide what to do here, you may want to retry a number of times,
    # but for this example just break
    break
  fi

  # lsof returned 1 but didn't print an error string, assume the file is open
  sleep 1
done

if [ -z "$err_str" ]; then
  # file has been closed, move it
  mv /path/to/file /destination/path
fi

Aktualisieren

Wie unten von @JohnWHSmith angemerkt, würde das sicherste Design immer einen lsof verwenden Schleife wie oben, da es möglich ist, dass mehr als ein Prozess die Datei zum Schreiben geöffnet hat (ein Beispielfall könnte ein schlecht geschriebener Indizierungs-Daemon sein, der Dateien mit dem Lese-/Schreib-Flag öffnet, obwohl sie eigentlich nur gelesen werden sollten). inotifywait kann aber immer noch anstelle von sleep verwendet werden, ersetzen Sie einfach die sleep-Zeile durch inotifywait -e close /path/to/file .


Als alternativer Ansatz ist dies der perfekte Fall für eine Pipe - Der zweite Prozess verarbeitet die Ausgabe des ersten Prozesses, sobald sie verfügbar ist, anstatt zu warten, bis der vollständige Prozess abgeschlossen ist:

process1 input_file.dat | process2 > output_file.dat

Vorteile:

  • Allgemein viel schneller:
    • Muss nicht auf die Festplatte schreiben und von ihr lesen (dies kann vermieden werden, wenn Sie eine Ramdisk verwenden).
    • Sollte Maschinenressourcen umfassender nutzen.
  • Keine Zwischendatei zum Entfernen nach der Fertigstellung.
  • Kein komplexes Sperren notwendig, wie in OP.

Wenn Sie keine Möglichkeit haben, direkt eine Pipe zu erstellen, aber GNU Coreutils haben Sie können dies verwenden:

tail -F -n +0 input_file.dat | process2 > output_file.dat

Dadurch wird die Eingabedatei von Anfang an gelesen, egal wie weit Der erste Prozess besteht darin, die Datei zu schreiben (auch wenn sie noch nicht begonnen oder bereits abgeschlossen ist).


Linux
  1. Verschieben Sie Dateien im Linux-Terminal

  2. Linux – Dateiberechtigung nur ausführen?

  3. Wie erstelle ich eine Datei nur, wenn sie nicht existiert?

  4. Nur verschieben, wenn die Datei in einem Shell-Skript vorhanden ist

  5. So zeigen Sie offene Dateideskriptoren an, ohne den Befehl lsof zu verwenden

So verschieben Sie eine Datei unter Linux

Diff -r nur für bestimmte Dateitypen?

So verwenden Sie den Befehl lsof unter Linux

Der Linux Move File Befehl - leicht gemacht!

Grundlegende vi-Befehle (Spickzettel)

Zeile NUR zu einer Datei hinzufügen, wenn sie sich nicht bereits in der Datei befindet