Od lsof
strony man
Lsof zwraca jeden (1), jeśli wykryty zostanie jakikolwiek błąd, w tym błąd w zlokalizowaniu nazw poleceń, nazw plików, adresów lub plików internetowych, nazw logowania, plików NFS, PID, PGID lub UID, o których wyświetlenie został poproszony. Jeśli podano opcję -V, lsof wskaże elementy wyszukiwania, których nie udało się wyświetlić na liście.
To sugerowałoby, że twoja lsof failed for some other reason
klauzula nigdy nie zostanie wykonana.
Czy próbowałeś właśnie przenieść plik, gdy proces zewnętrzny ma go jeszcze otwarty? Jeśli katalog docelowy znajduje się w tym samym systemie plików, nie powinno być z tym żadnych problemów, chyba że musisz uzyskać dostęp do oryginalnej ścieżki z trzeciego procesu, ponieważ i-węzeł pozostanie taki sam. W przeciwnym razie myślę, że mv
i tak się nie uda.
Jeśli naprawdę musisz poczekać, aż proces zewnętrzny zakończy się plikiem, lepiej użyć polecenia blokującego zamiast wielokrotnego odpytywania. W systemie Linux możesz inotifywait
do tego użyć . Na przykład:
inotifywait -e close_write /path/to/file
Jeśli musisz użyć lsof
(być może do przenoszenia), możesz wypróbować coś takiego:
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
Aktualizacja
Jak zauważył @JohnWHSmith poniżej, najbezpieczniejszy projekt zawsze używałby lsof
pętli jak wyżej, ponieważ możliwe jest, że więcej niż jeden proces otworzyłby plik do zapisu (przykładowym przypadkiem może być źle napisany demon indeksujący, który otwiera pliki z odczytem / napisz flagę, kiedy powinna być tylko do odczytu). inotifywait
nadal można go używać zamiast snu, wystarczy wymienić linię snu na inotifywait -e close /path/to/file
.