我想在外部进程关闭后立即移动由外部进程创建的大文件。
这个测试命令正确吗?
if lsof "/file/name"
then
# file is open, don't touch it!
else
if [ 1 -eq $? ]
then
# file is closed
mv /file/name /other/file/name
else
# lsof failed for some other reason
fi
fi
编辑:该文件代表一个数据集,我必须等到它完成才能移动它,以便另一个程序可以对其进行操作。这就是为什么我需要知道外部进程是否已完成该文件。
答案1
从lsof
手册页
如果检测到任何错误,包括未能找到要求列出的命令名、文件名、Internet 地址或文件、登录名、NFS 文件、PID、PGID 或 UID,Lsof 将返回一 (1)。如果指定了 -V 选项,lsof 将指示它未能列出的搜索项。
所以这表明你的lsof failed for some other reason
条款永远不会被执行。
您是否尝试过在外部进程仍打开文件的情况下移动文件?如果目标目录位于同一文件系统上,那么这样做应该没有问题,除非您需要从第三个进程的原始路径下访问它,因为底层 inode 将保持不变。否则我想mv
无论如何都会失败。
如果您确实需要等到外部进程完成文件处理,那么最好使用阻塞命令,而不是重复轮询。在 Linux 上,您可以使用inotifywait
它。例如:
inotifywait -e close_write /path/to/file
如果您必须使用lsof
(也许是为了便携性),您可以尝试以下操作:
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
更新
正如所指出的@约翰·WHS史密斯下面,最安全的设计总是使用lsof
如上所述的循环,因为可能有多个进程打开文件进行写入(一个示例情况可能是一个写得不好的索引守护进程,它在打开文件时带有读/写标志实际上应该是只读的)。inotifywait
不过仍然可以用来代替 sleep,只需将 sleep 行替换为inotifywait -e close /path/to/file
.
答案2
作为一种替代方法,这是一个完美的案例管道- 第二个进程将在第一个进程的输出可用时立即对其进行处理,而不是等待整个进程完成:
process1 input_file.dat | process2 > output_file.dat
优点:
- 一般来说要快得多:
- 不必对磁盘进行写入和读取(如果您使用 ramdisk,则可以避免这种情况)。
- 应该更充分地利用机器资源。
- 完成后无需删除中间文件。
- 不需要像OP中那样复杂的锁定。
如果您无法直接创建管道,但您有GNU 核心工具你可以使用这个:
tail -F -n +0 input_file.dat | process2 > output_file.dat
这将从头开始读取输入文件,无论多远第一个过程是通过写入文件(即使它尚未开始或已经完成)。