当 sed 找到字符串时如何停止尾部?

当 sed 找到字符串时如何停止尾部?

我想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 机器,您会发现一切都井然有序,并且不需要任何东西killtail会自行终止:

debian$ tail -f file | sed /2/q
1
2
debian$ # WOW!

这是因为tailGNU 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 ();

[事实上,其他系统可能会POLLHUPPOLLHUP|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

进而两个都 tailsed成功退出。因此,您自己的示例(至少在我的计算机上)与您所描述的完全一样。为了进一步验证这一点,给出以下文件

one
two
three
four

我没有得到任何输出,并且命令挂起,等待special string.然后,当我使用echo special string >> logfile来自单独终端的命令添加它时,原始命令再次成功退出。

所以一切看起来都正常,对吧?如果没有,请告诉我您的期望。无论如何,感谢您向我学习了一个很酷的新技巧,我将来无疑会使用它!

相关内容