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).