Bash 我怎样才能清楚地告诉tail-f它已经完成了?

Bash 我怎样才能清楚地告诉tail-f它已经完成了?,bash,unix,cygwin,gzip,tail,Bash,Unix,Cygwin,Gzip,Tail,在创建日志文件时,我正在将其复制到远程服务器 tail -f LOGILE | gzip -c >> /faraway/log.gz 然而,当原始日志文件关闭并移动到存储目录时,我的tail-f似乎得到了一些奇怪的数据 如何确保tail-f干净地停止,并且压缩文件/faraway/log.gz是LOGFILE的真实副本 编辑1 我又挖了一点 /faraway/log.gz终止不正确-修复消息执行了一半。这一定是因为我调用了上面的整个管道命令 如果忽略最后一行,则原始日志文件和log

在创建日志文件时,我正在将其复制到远程服务器

tail -f LOGILE | gzip -c >> /faraway/log.gz
然而,当原始日志文件关闭并移动到存储目录时,我的tail-f似乎得到了一些奇怪的数据

如何确保tail-f干净地停止,并且压缩文件/faraway/log.gz是LOGFILE的真实副本

编辑1

我又挖了一点

/faraway/log.gz终止不正确-修复消息执行了一半。这一定是因为我调用了上面的整个管道命令

如果忽略最后一行,则原始日志文件和log.gz完全匹配!这是一个跨越大西洋传输的40G文件

这给我留下了深刻的印象,因为它正是我想要的。有没有读者认为我在这种情况下很幸运——这在将来可能行不通


现在,我只需要清楚地了解一下gzip。也许按照下面的建议将kill-9发送到tail-PID会允许GZIP正确完成压缩。

要获得完整副本,请使用

tail -n +1 -f your file
如果不使用-n+1选项,则只获取文件的尾部

但这并不能解决删除/移动文件的问题。。事实上,删除/移动文件问题是IPC进程间通信问题,或者是进程间协作问题。如果没有其他流程的正确行为模型,则无法解决问题

例如,如果另一个程序将日志文件复制到其他地方,然后删除当前的日志文件,那么该程序会将输出记录到新的日志文件中。。。很明显,你的尾巴无法读取这些输出

值得一提的是unix和类unix系统的一个相关功能:

当一个文件被进程a打开以供读取,但随后被进程a删除时 过程B中,物理内容不会立即删除, 因为它的引用计数不是零,所以有人仍在使用它,即。 进程A。进程A仍然可以访问该文件,直到它关闭 文件移动文件是另一个问题:如果进程B移动 文件到同一物理文件系统注意:您可能有许多 物理文件系统连接到您的系统上,进程A仍然可以 访问该文件,即使该文件正在增长。这种搬家方式很有趣 只需更改名称路径名+文件名,仅此而已。这个 unix中文件a.k.a.i-node的标识不会更改。然而 如果文件被移动到另一个物理文件系统(本地或远程), 就好像文件被复制然后被删除一样。所以删除规则 以上提到的都可以应用

您提到的缺行问题很有趣,可能需要对生成和移动/删除日志文件的程序/进程的行为进行更多分析

-更新-

很高兴看到你取得了一些进步。正如我所说的,像tail这样的进程在运行之后仍然可以访问数据 在类unix系统中,该文件将被删除

你可以用 echo$BASHPID>/tmp/PID_tail;exec tail-n+1-f yourLogFile | gzip-c->yourZipFile.gz

gzip日志文件,并通过

kill -TERM `cat /tmp/PID_tail`
gzip应该自己完成,没有错误。即使你担心gzip会收到坏消息 管道信号,可以使用此替代方法防止管道破裂:

 (  ( echo $BASHPID > /tmp/PID_tail; exec tail -n + 1 -f yourLogFile ) ; true ) | gzip -c - > yourZipFile.gz
破裂的管道由一个真实的保护,它不打印任何东西,但会自动结束。

来自:Emphasis mine

使用-follow-f,tail默认为跟随文件 描述符,这意味着即使尾部文件被重命名, 尾巴将继续跟踪它的末端。此默认行为是 当您真的想要跟踪 文件,而不是文件描述符,例如日志旋转。使用 -在这种情况下follow=name。这将导致tail跟踪指定的 文件的命名、删除和创建方式

因此,您提出的问题解决方案是使用:

tail --follow=name LOGILE | gzip -c >> /faraway/log.gz

这样,当文件被删除时,tail将停止读取它。

您能为这种情况定义奇怪的数据吗?日志文件是如何关闭的?tail-f将继续从文件中读取,即使您修改了它。你需要给tail一些停止跟踪文件的理由。如果你想要一个完整的文件副本,tail-f对于这个作业来说是错误的工具,请全部停止。除非您保证在启动流程时它是空的,否则您甚至不可能抓住开头——并且除非您的gunzip实现是基于重新启动压缩流的预期而构建的,否则您也会在那里得到惊喜。@EtanReisner那里似乎少了一两行。一旦日志文件被移动,我就用ctrl-c终止进程。我需要向tail-f发送一个信号,表示日志文件已完成-让gzip特写。@ManInMoon,它似乎只起作用,因为您还没有测试其他角落案例。存在用于远程日志记录的专用工具。如果你能控制所有修改/访问/删除文件的程序,我相信
能满足你的目的。你的描述更清楚,但需要更多的澄清。也许您可以这样表述您的目标:程序A@machine A写入日志文件X,程序B@machine A读取日志文件X,等等。。他们将以什么顺序写入/读取/删除/移动,tail命令放在什么位置,在这个顺序中,以及在哪个程序中。。。就像tail在程序B@host B中一样。。。等与其说我在复制…,不如说程序A在复制…。假设您使用的是bash,要获得要终止发送信号的tail的PID,请使用echo$BASHPID>/tmp/PID_tail;tail-n+1-f您的文件| gzip…参考上面的注释:如果您运行exec tail-n+1,这肯定会起作用;否则,您将依赖于可能存在或不存在的优化。你知道哪个版本的bash自动执行子shell的最后一个组件吗?参考上面的评论:不太清楚你的意思。。。echo$BASHPID>。。。;尾巴…|gzip…&肯定会分叉两个过程,围绕|的每一侧一个。在地下室里面。。。这个当然,这意味着这两个部分将在同一个子shell中执行,因为它必须按顺序执行。是的,但您不需要尾部的父shell的pid,而是尾部本身的pid,不是吗?如果您运行tail而不是exec tail,那么您就有可能获得tail的父进程,除非您的bash版本自动将最后一个进程设置为exec.Ya。你是对的。我在这里重新发帖更正我的评论:假设您使用的是bash,要获得要终止发送信号的tail的PID,请使用echo$BASHPID>/tmp/PID\u tail;exec tail-n+1-f您的文件| gzip。。。