确定文件是否正在写入过程中?

Jak*_*son 32 linux bash tar

我需要部署一个自动化进程(通过 1 分钟的 cron 脚本)来查找特定目录中的 tar 文件。如果找到 tar 文件,则将其解压缩到适当的位置,然后删除 tar 文件。

tar 文件会通过 SSH 从另一台服务器自动复制到此服务器。在某些情况下,tar 文件非常大,有很多文件。

我期望遇到的问题:如果将 tar 文件复制到服务器需要 1 分钟以上,并且 cron 脚本每分钟运行一次,它将看到 .tar.gz 文件并尝试执行解压它,即使 tar 文件仍在写入过程中。

有没有办法(通过 bash 命令)来测试当前是否正在写入文件,或者它是否只是部分文件等?

我想到的另一种方法是将文件复制为不同的文件扩展名(如.tar.gz.part),然后.tar.gz在传输完成后重命名为。但我想我会尝试弄清楚是否有一种简单的方法可以首先在命令行中确定文件是否完整......有任何线索吗?

Mik*_*eyB 16

最好的办法是用来lsof确定文件是否已被任何进程打开:

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog
Run Code Online (Sandbox Code Playgroud)

你不能轻易判断它是否正在被写入,但如果它正在被写入,它必须是打开的。


编辑:让我们在这里解决实际问题,而不是尝试实施建议的解决方案!

使用 rsync 传输文件:

? ? rsync -e ssh remote:big.tar.gz .
Run Code Online (Sandbox Code Playgroud)

这样,文件不会复制到现有文件之上,而是复制到临时文件 ( .big.tar.gz.XXXXXX) 中,直到传输完成,然后移动到位。


Ale*_*lex 13

您走对了,重命名文件是一个原子操作,因此上传后执行重命名简单、优雅且不易出错。我能想到的另一种方法是用来lsof | grep filename.tar.gz检查文件是否正在被另一个进程访问。

  • (`lsof filename.tar.gz` 比 `lsof | grep filename.tar.gz` 更高效、更准确) (11认同)

And*_*nle 6

有点旧,但大多数答案完全没有抓住问题的重点:

但是我想我会尝试弄清楚是否有一种简单的方法可以首先在命令行中确定文件是否完整......

一般来说,没有。您只是没有足够的信息来确定这一点。

因为确定文件已关闭与确定文件是否完整不同。例如,如果连接在传输过程中丢失,文件将被“关闭”。

只有@Alex 的回答是正确的。甚至他也lsof有点喜欢使用。

要确定文件是否已完整传输,成功传输需要更多数据。如:

我想到的另一种方法是将文件复制为不同的文件扩展名(如.tar.gz.part),然后.tar.gz在传输完成后重命名为。

这是传达文件已完全成功传输的完美方式。您还可以将文件从一个目录移动到另一个目录,只要您保持在同一个文件系统中。或者让发件人发送一个空filename.done文件来表示完成。

但是所有方法都必须依靠发送方以某种方式发出传输已成功完成的信号。因为只有发件人有这些信息。

某些文件格式(例如 PDF)中包含数据,可让您确定文件是否完整。但是您必须打开并阅读几乎整个文件才能找到答案。

lsof只会告诉您该文件不再打开 - 它不会告诉您为什么它不再打开。它也不会告诉您文件应该有多大。


Kyl*_*yle 5

最好的方法是使用incron(“inotify cron 系统”)。它允许您在目录上设置inotify监视,然后通知您文件操作。在这种情况下,您应该查看目录中的 close_write。这将允许您在写入后关闭文件后运行您的命令。