为什么 `tail -f … | grep -q …` 找到匹配项后不会退出?

为什么 `tail -f … | grep -q …` 找到匹配项后不会退出?

我正在做一个非常标准的tail+ grep

tail -f some_log_file.txt | grep -q known-string

如果我运行不带以下选项的命令-q

tail -f some_log_file.txt | grep known-string

我看到输出:

[Tue Feb 12 11:32:45 2019] known-string.

所以我知道 grep 匹配了。但是当我添加-qgrep 命令时,它并没有退出,而是挂在那里等待更多输出……尽管手册页说“如果找到任何匹配项,它将立即以零状态退出”:

   -q, --quiet, --silent
          Quiet;  do  not  write  anything  to  standard   output.    Exit
          immediately  with  zero status if any match is found, even if an
          error was detected.  Also see the -s or --no-messages option.

有人能解释一下为什么-q我的 grep 不会退出吗?我试图将 a 链接&& beep到最后,这样grep当找到匹配项时就会发出哔哔声,但除非我能让它退出,否则不会起作用。

答案1

来自 StackOverflow 帖子 ‘grep -q’ 不会以 ‘tail -f’ 退出

tail -f将读取一个文件并显示后来添加的行,它不会终止(除非SIGTERM发送类似的信号)。grep不是这里的阻塞部分,tail -f是。grep将从管道读取直到它关闭,但它永远不会因为tail -f不会退出并保持管道打开而停止。


解决您问题的方法可能是(未经测试并且很可能表现不佳):

tail -f logfile | while read line; do
  echo $line | grep -q 'find me to quit' && break;
done

您将在链接的帖子中找到更多信息和解决方案。

答案2

grep确实退出并且管道消失,尽管tail继续运行。此错误报告日志从与您的非常相似的用例开始:

我想使用tailgrep跟踪文件直到出现特定模式。但完成tail后不会退出。grep

$ echo xxx > /tmp/blabla
$ tail -f /tmp/blabla |grep -m1 --line-buffered "xxx"
xxx

现在tail仍尝试读取,只有我再次写入时才会退出/tmp/blabla

事情就该如此吗?

那里的解释:

tail确实会在 SIGPIPE 上退出,但是它只会在 上获取信号write(),因此您需要在tail退出之前在文件中获取更多数据。

据我所知,这种机制非常常见。许多工具都存在他们尝试向损坏的管道写入某些内容,这不是错误。

然后这个愿望就来了:

这是一个公平的观点tail,因为它可以永远存在,所以应该采取特殊措施来对管道另一端的消失做出反应。

最后:

实现于:
https://git.sv.gnu.org/cgit/coreutils.git/commit/?id=v8.27-42-gce0415f

确实,当我尝试使用tailGNU coreutils 8.28 重现您的问题时,我无法重现。该工具立即退出。

相关内容