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

Abh*_*ngh 2 shell tail

我想tail在找到匹配项后终止命令,直到所有行都写入另一个文件。

tail -f logfile | sed '/special string/q'  | tee output.txt
Run Code Online (Sandbox Code Playgroud)

Output.txt 将包含直到找到特殊字符串为止的行。但问题是,之后我想结束命令tail

小智 6

你应该明确地杀死它

seq 1 10 > file
tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; } | tee output
Run Code Online (Sandbox Code Playgroud)

pkill -PIPE -xg0 tail方法

向与我们属于同一进程组的SIGPIPE进程发送一个信号。tail

tail这假设同一进程组中没有其他进程正在运行。如果该命令是从交互式终端(从具有作业控制的 shell)运行的,那么它应该是安全的,因为每个管道都在其自己的进程组(也称为作业)中运行。在没有作业控制的 shell 中(例如在脚本中),我们可以将管道包装在单独的 shell 中,其中显式打开作业控制:

sh -mc 'tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; }' | tee output
Run Code Online (Sandbox Code Playgroud)

但 GNU 尾巴会自杀

如果您使用的是带有 bash 和 coreutils 的 Linux 机器,您会发现一切都井然有序,并且不需要任何kill东西;tail会自行终止:

debian$ tail -f file | sed /2/q
1
2
debian$ # WOW!
Run Code Online (Sandbox Code Playgroud)

这是因为tailGNU coreutils 正在使用一个聪明的技巧来确定它的 stdout 是否仍然可写:它正在轮询它是否处于“准备读取”条件,只有在出现错误的情况下才会在管道的写入端发生这种情况,例如它的另一端已关闭。如果是这样的话,那就tail用信号杀死自己吧SIGPIPE。引用其源代码

seq 1 10 > file
tail -f file | { sed /7/q; pkill -PIPE -xg0 tail; } | tee output
Run Code Online (Sandbox Code Playgroud)

[事实上,其他系统可能会POLLHUPPOLLHUP|POLLIN代替POLLERR,但这在实践中并不重要]

GNU tail 只在管道上执行此操作,而不是在套接字或 tty 上执行此操作(这意味着这不适用于 ksh93,它使用膝部 unix 域套接字来实现其“管道”)。

另外(据我所知)只有 GNU 才tail这样做,而且只是从8.28版本开始;即使在 Linux 上,busyboxtail也没有。

这意味着使用tail -f | quit_at_some_point(从这里的许多答案来看)仍然是非常偶然的,并且实际上可能永远不会终止。