我想tail
在找到匹配项后终止命令,直到所有行都写入另一个文件。
tail -f logfile | sed '/special string/q' | tee output.txt
Output.txt 将包含直到找到特殊字符串为止的行。但问题是,之后我想结束tail
命令。
答案1
你应该明确地杀死它
seq 1 10 > file
tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; } | tee output
pkill -PIPE -xg0 tail
方法
向与我们属于同一进程组的
SIGPIPE
进程发送一个信号。tail
tail
这假设同一进程组中没有其他进程正在运行。如果该命令是从交互式终端(从具有作业控制的 shell)运行的,那么它应该是安全的,因为每个管道都在其自己的进程组(也称为作业)中运行。在没有作业控制的 shell 中(例如在脚本中),我们可以将管道包装在单独的 shell 中,其中显式打开作业控制:
sh -mc 'tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; }' | tee output
但 GNU 尾巴会自杀
如果您使用的是带有 bash 和 coreutils 的 Linux 机器,您会发现一切都井然有序,并且不需要任何东西kill
;tail
会自行终止:
debian$ tail -f file | sed /2/q
1
2
debian$ # WOW!
这是因为tail
GNU coreutils 使用了一个聪明的技巧来确定它的标准输出是否仍然可写:它正在轮询“准备好阅读“条件,只有在发生错误的情况下才会在管道的写入端发生,就像当其另一端已关闭时一样。如果是这种情况,则tail
只需用信号杀死自己即可SIGPIPE
。引用其源代码:
FD_SET (STDOUT_FILENO, &rfd);
/* readable event on STDOUT is equivalent to POLLERR,
and implies an error condition on output like broken pipe. */
if (select (STDOUT_FILENO + 1, &rfd, NULL, NULL, &delay) == 1)
die_pipe ();
[事实上,其他系统可能会POLLHUP
或POLLHUP|POLLIN
代替POLLERR
,但这在实践中并不重要]
GNU tail 只在管道上执行此操作,而不是在套接字或 tty 上执行此操作(这意味着这不适用于 ksh93,它使用膝部 unix 域套接字来实现其“管道”)。
另外(据我所知)只有 GNUtail
才这样做,而且只是从版本开始8.28;即使在 Linux 上,busyboxtail
也没有。
这意味着使用tail -f | quit_at_some_point
(从这里的许多答案来看)仍然是非常偶然的,并且实际上可能永远不会终止。
答案2
鉴于以下情况logfile
:
one
two
three
special string
four
以及以下命令
$ tail -f logfile | sed '/special string/q' | tee output.txt
我得到以下输出:
one
two
three
special string
进而两个都 tail
并sed
成功退出。因此,您自己的示例(至少在我的计算机上)与您所描述的完全一样。为了进一步验证这一点,给出以下文件
one
two
three
four
我没有得到任何输出,并且命令挂起,等待special string
.然后,当我使用echo special string >> logfile
来自单独终端的命令添加它时,原始命令再次成功退出。
所以一切看起来都正常,对吧?如果没有,请告诉我您的期望。无论如何,感谢您向我学习了一个很酷的新技巧,我将来无疑会使用它!