确定文件是否正在被写入?

确定文件是否正在被写入?

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

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

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

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

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

答案1

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

答案2

最好的办法是使用来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

您无法轻易判断它是否正在被写入,但如果正在被写入,它必须是打开的。


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

使用 rsync 传输文件:

○ → rsync -e ssh remote:big.tar.gz .

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

答案3

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

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

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

因为确定文件是关闭不同于确定文件是否所有的。例如,如果在传输过程中连接丢失,文件将被“关闭”。

只有@Alex 的回答是正确的。甚至他也因使用lsof“something”而受骗。

要判断文件是否已完整、成功传输,需要更多数据。例如:

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

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

但所有方法都必须依赖发送方以某种方式发出信号,表明传输已成功完成。因为只有发送方才拥有该信息。

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

lsof只会告诉你文件不再打开 - 它不会告诉你为什么它不再处于打开状态。它也不会告诉你文件应该有多大。

答案4

lsof 似乎可以检测文件在什么模式下打开:

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

看到 1w 了吗?这意味着文件描述符编号为 1,模式为 w(即写入)。

相关内容