移动文件,但前提是它已关闭

Pet*_*vac 10 linux monitoring shell-script lsof open-files

我想在外部进程关闭后立即移动它创建的大文件。

这个测试命令正确吗?

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
Run Code Online (Sandbox Code Playgroud)

编辑:该文件代表一个数据集,我必须等到它完成才能移动它,以便另一个程序可以对其进行操作。这就是为什么我需要知道外部进程是否完成了文件。

Gra*_*eme 11

lsof手册页

如果检测到任何错误,Lsof 将返回一 (1),包括无法定位命令名、文件名、Internet 地址或文件、登录名、NFS 文件、PID、PGID 或要求列出的 UID。如果指定了 -V 选项,lsof 将指示它未能列出的搜索项。

所以这表明你的lsof failed for some other reason条款永远不会被执行。

您是否尝试过在外部进程仍然打开时移动文件?如果目标目录在同一个文件系统上,那么这样做应该没有问题,除非您需要从第三个进程的原始路径下访问它,因为底层 inode 将保持不变。否则我认为mv无论如何都会失败。

如果你真的需要等到你的外部进程处理完文件,你最好使用阻塞命令而不是重复轮询。在 Linux 上,您可以使用inotifywait它。例如:

 inotifywait -e close_write /path/to/file
Run Code Online (Sandbox Code Playgroud)

如果您必须使用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
Run Code Online (Sandbox Code Playgroud)

更新

正如下面@JohnWHSmith所指出的,最安全的设计将始终使用上述lsof循环,因为可能会有多个进程打开文件进行写入(示例情况可能是编写不良的索引守护进程,它使用读取打开文件) /write 标志,当它真的应该是只读的)。inotifywait仍然可以代替 sleep 使用,只需将 sleep 行替换为inotifywait -e close /path/to/file.