Từ lsof
trang người đàn ông
Lsof trả về một (1) nếu phát hiện bất kỳ lỗi nào, bao gồm cả việc không tìm thấy tên lệnh, tên tệp, địa chỉ Internet hoặc tệp, tên đăng nhập, tệp NFS, PID, PGID hoặc UID mà nó được yêu cầu liệt kê. Nếu tùy chọn -V được chỉ định, lsof sẽ chỉ ra các mục tìm kiếm mà nó không thể liệt kê.
Vì vậy, điều đó sẽ gợi ý rằng lsof failed for some other reason
mệnh đề của bạn sẽ không bao giờ được thực thi.
Bạn đã thử chỉ di chuyển tệp trong khi quá trình bên ngoài của bạn vẫn mở nó? Nếu thư mục đích nằm trên cùng một hệ thống tệp, thì sẽ không có vấn đề gì khi thực hiện điều đó trừ khi bạn cần truy cập nó theo đường dẫn gốc từ quy trình thứ ba vì nút inode bên dưới sẽ giữ nguyên. Nếu không tôi nghĩ mv
dù sao cũng sẽ thất bại.
Nếu bạn thực sự cần đợi cho đến khi quá trình bên ngoài của bạn kết thúc với tệp, bạn tốt hơn nên sử dụng một lệnh chặn thay vì bỏ phiếu nhiều lần. Trên Linux, bạn có thể sử dụng inotifywait
cho việc này. Ví dụ:
inotifywait -e close_write /path/to/file
Nếu bạn phải sử dụng lsof
(có thể cho tính di động), bạn có thể thử một cái gì đó như:
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
Cập nhật
Như được lưu ý bởi @JohnWHSmith bên dưới, thiết kế an toàn nhất sẽ luôn sử dụng một lsof
vòng lặp như trên vì có thể có nhiều hơn một quy trình sẽ mở tệp để viết (một trường hợp ví dụ có thể là một trình nền lập chỉ mục được viết kém, mở tệp bằng cách đọc / viết cờ khi nó thực sự chỉ nên đọc). inotifywait
Vẫn có thể được sử dụng thay vì ngủ, chỉ cần thay thế dòng ngủ bằng inotifywait -e close /path/to/file
.