我需要部署一个自动化进程(通过 1 分钟的 cron 脚本)来查找特定目录中的 tar 文件。如果找到 tar 文件,则会将其解压缩到适当的位置,然后删除 tar 文件。
tar 文件通过 SSH 从另一台服务器自动复制到该服务器。在某些情况下,tar 文件非常大,包含很多文件。
我预计会遇到的问题:如果将 tar 文件复制到服务器需要 > 1 分钟,并且 cron 脚本每分钟运行一次,它将看到 .tar.gz 文件并尝试执行解压它,即使 tar 文件仍在写入过程中。
有什么方法(通过 bash 命令)来测试当前是否正在写入文件,或者它是否只是部分文件等?
我想到的一种替代方法是将文件复制为不同的文件扩展名(如.tar.gz.part
),然后.tar.gz
在传输完成后重命名为。但是我想我会尝试弄清楚是否有一种方法可以首先在命令行确定文件是否完整......有什么线索吗?
最好的办法是使用
lsof
确定文件是否已被任何进程打开:您无法轻易判断它是否正在被写入,但如果正在被写入,则它必须是打开的。
编辑:让我们在这里解决实际问题,而不是尝试实施建议的解决方案!
使用 rsync 传输文件:
这样,文件不会复制到现有文件之上,而是复制到临时文件 (
.big.tar.gz.XXXXXX
) 中,直到传输完成,然后移动到位。你在正确的轨道上,重命名文件是一个原子操作,所以上传后执行重命名简单、优雅且不易出错。我能想到的另一种方法是使用
lsof | grep filename.tar.gz
检查文件是否正在被另一个进程访问。有点旧,但大多数答案完全没有抓住问题的要点:
一般来说,没有。您根本没有足够的信息来确定这一点。
因为确定文件已关闭与确定文件是否完整不同。例如,如果连接在传输中途丢失,文件将“关闭”。
只有@Alex 的回答是正确的。甚至他也因为使用
lsof
了一些东西而倒下了。要确定文件是否已完全、成功传输,需要更多数据。如:
这是传达文件已完全成功传输的完美方式。你也可以将文件从一个目录移动到另一个目录,只要你在同一个文件系统中。或者让发件人发送一个空
filename.done
文件来表示完成。但是所有方法都必须依赖于发送方以某种方式发出传输已成功完成的信号。因为只有发件人拥有该信息。
某些文件格式(如 PDF)中包含数据,可让您确定文件是否完整。但是您必须打开并阅读几乎整个文件才能找到答案。
lsof
只会告诉您该文件不再打开 - 它不会告诉您为什么它不再打开。它也不会告诉您文件应该有多大。最好的方法是使用incron(“inotify cron 系统”)。它允许您在目录上设置一个inotify监视,然后通知您文件操作。在这种情况下,您应该查看目录以查找 close_write。一旦文件在写入后关闭,这将允许您运行命令。
似乎 lsof 可以检测文件在什么模式下打开:
看到上面写着 1w 的地方了吗?这意味着文件描述符编号为 1,模式为 w,即写入。
使用
inotifywait
可以实现你所追求的——它有能力在执行命令之前等到文件写入完成。以下将持续监视文件夹中的新文件,并在写入文件完成后循环执行命令。
有关更多配置选项,请参阅https://linux.die.net/man/1/inotifywatch
我使用一个 python 脚本来迭代大小检查,直到它在不同时间的 2 次迭代中相同(在我的例子中,检查之间有 0.05 秒的差异,工作完成了!):