如何“ grep”连续流?


729

可以grep在连续流上使用吗?

我的意思是说是一条tail -f <file>命令,但grep在输出中仅保留我感兴趣的行。

我已经尝试过,tail -f <file> | grep pattern但是似乎grep只能在tail完成后才能执行,也就是说永远不会执行。


9
生成文件的程序很可能没有刷新其输出。
Steve-o

tail -f file作品(我实时看到了新的输出)
Matthieu Napoli


@Luc确实没想到
Matthieu Napoli

输入流中可能没有换行吗?如果是这样,则grep将不会继续。
林奇

Answers:


1326

grep使用BSD grep(FreeBSD,Mac OS X等)时,打开的行缓冲模式。

tail -f file | grep --line-buffered my_pattern

您无需为GNU grep(几乎在任何Linux上使用)执行此操作,因为它会默认刷新(对于其他类似Unix的版本,如SmartOS,AIX或QNX,则为YMMV)。


3
@MichaelNiemand您可以使用tail -F文件| grep --line-buffered my_pattern
jcfrei

47
@MichaelGoldshteyn放轻松。人们之所以支持它,是因为他们在Google上搜索“ grep行缓冲”时找到了此页面,从而为他们解决了一个问题,而这可能并不是问题所在。
Raine

4
我来到这里尝试grep的输出strace。没有--line-buffered,它将无法正常工作。
sjas 2013年

5
@MichaelGoldshteyn(和他的评论的支持者):我一直遇到这个问题tail -f | grep,并--line-buffered为我解决了这个问题(在Ubuntu 14.04,GNU grep版本2.16上)。哪里实现了“如果stdout是tty,则使用行缓冲”逻辑?在git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c中line_buffered仅由参数解析器设置。
Aasmund Eldhuset

8
@MichaelGoldshteyn我在使用BSD grep的macOS上,没有--line-buffered我没有输出。但是,经过测试,看起来GNU grep可以完成您所描述的工作。因此,与大多数Unix一样,它取决于您平台的实现。由于问题未指定平台,因此您的信息似乎是错误的-在查看了BSD grep的代码并将其与GNU grep进行比较之后,该行为肯定由--line-buffered选项控制。只是默认情况下只有GNU grep刷新。
理查德·韦特

118

tail -f <file> | grep <pattern>一直都在用。

它将等到grep刷新,而不是等到完成(我正在使用Ubuntu)。


4
这可能会持续相当长的一段时间,因此请不要急躁。
glglgl 2011年

大概需要多长时间?
Matthieu Napoli

@Matthieu:主要取决于grep的用途以及操作系统上的缓冲区大小。如果grep每隔几个小时只匹配一个短字符串,则将在第一次刷新前几天。
2011年

13
尾部不使用输出缓冲,而grep则使用。
XzKto 2011年

7
不,在将输出发送到tty设备时,grep不会进行输出缓冲,这在此答案中很明显。它做行缓冲!这是正确的答案,应该是公认的答案。有关更多详细信息,请参见我对当前接受的(错误的)答案的较长评论。
Michael Goldshteyn

67

我认为您的问题是grep使用了一些输出缓冲。尝试

tail -f file | stdbuf -o0 grep my_pattern

它将grep的输出缓冲模式设置为unbuffered。


7
这样做的好处是,除了,它还可以用于许多其他命令grep
Peter V.Mørch'12年

4
但是,正如我在玩了更多之后发现的那样,有些命令仅在连接到tty时才刷新其输出,为此,unbuffer(在expect-devdebian 的软件包中)是king。因此,我将对stdbuf使用unbuffer。
Peter V.Mørch'12年

5
@Peter V.Mørch是的,您是对的,在stdbuf无法实现的地方,无缓冲有时可以起作用。但是我认为您正在尝试找到一个“魔术”程序,该程序将始终解决您的问题而不是理解您的问题。创建虚拟tty是无关的任务。Stdbuf确实完成了我们想要的事情(设置了标准输出缓冲区以提供值),而unbuffer做了很多我们可能不想要的隐藏东西(top与stdbuf和unbuffer 进行交互)。确实没有“魔术”解决方案:取消缓冲有时也会失败,例如awk使用不同的缓冲实现(stdbuf也将失败)。
XzKto 2012年

2
“但是我认为您正在尝试找到一个“魔术”程序,它将始终解决您的问题而不是理解您的问题。” - 我想你是正确的!;-)
Peter V.Mørch2012年

1
有关stdbuf像素缓冲,解缓冲和stdio缓冲的更多信息,请访问pixelbeat.org/programming/stdio_buffering
Tor Klingberg,2015年

13

如果您想在整个文件中查找匹配项(而不仅仅是尾部),并且希望它坐下来等待任何新的匹配项,则效果很好:

tail -c +0 -f <file> | grep --line-buffered <pattern>

-c +0标志表示输出应从文件的开头()开始0字节(-c+


12

在大多数情况下,您可以tail -f /var/log/some.log |grep foo并且它将正常工作。

如果您需要在一个运行中的日志文件上使用多次抓取,但发现没有任何输出,则可能需要将--line-buffered开关插入中间的 grep中,如下所示:

tail -f /var/log/some.log | grep --line-buffered foo | grep bar

7

您可能将此答案视为增强..通常我正在使用

tail -F <fileName> | grep --line-buffered  <pattern> -A 3 -B 5

-F在文件旋转的情况下更好(如果文件旋转,-f将无法正常工作)

-A和-B对于在模式发生之前和之后获取行很有用..这些块将出现在虚线分隔符之间

但对我来说,我更喜欢执行以下操作

tail -F <file> | less

如果要在流式日志中进行搜索,这将非常有用。我的意思是来回向前看


4
grep -C 3 <pattern>,如果N相同,则替换-A <N>和-B <N>。
AKS

6

没看到有人为此提供我通常的建议:

less +F <file>
ctrl + c
/<search term>
<enter>
shift + f

我更喜欢这样做,因为您可以使用它ctrl + c随时停止和浏览文件,然后单击shift + f以返回实时流式搜索。


4

sed是更好的选择(编辑器)

tail -n0 -f <file> | sed -n '/search string/p'

然后,如果您希望在找到特定字符串后退出tail命令:

tail --pid=$(($BASHPID+1)) -n0 -f <file> | sed -n '/search string/{p; q}'

显然是一种批评:$ BASHPID将是tail命令的进程ID。sed命令位于管道尾部之后,因此sed进程ID为$ BASHPID + 1。


1
$BASHPID+1在许多情况下,假设系统()上启动的下一个进程将是您的,这是错误的,这并不能解决缓冲问题,这可能是OP试图解决的问题。特别是,sedgrep这里推荐似乎只是(可疑)偏好问题。(如果这是您要传达的要点,您可能会得到p;q举止grep -m 1。)
Tripleee

正常运行,sed命令在准备好后立即打印每行,而grep命令--line-buffered没有。我衷心不懂减1
MUY比利时

迄今为止已经确定,缓冲是grep的问题。无需特殊操作即可使用sed处理行缓冲,这是默认行为,因此,我重点介绍了字。的确,不能保证 $ BASHPID + 1将是正确的pid,但是由于pid分配是顺序的,并且在管道命令之后立即分配了一个pid,因此绝对有可能。
Christian Herr

1

是的,这实际上可以正常工作。Grep大多数Unix命令一次只能在一行上对流进行操作。从尾部出来的每条线都将被分析并传递(如果匹配)。


2
这实际上是不正确的。如果grep是管道链中的最后一条命令,它将按照您的解释进行操作。但是,如果它在中间,它将一次缓冲大约8k的输出。
Mahmoud Al-Qudsi '16

1

这一条命令对我有用(Suse):

mail-srv:/var/log # tail -f /var/log/mail.info |grep --line-buffered LOGIN  >> logins_to_mail

收集登录邮件服务


-1

你当然不会成功

tail -f /var/log/foo.log |grep --line-buffered string2search

当您使用“ colortail”作为尾巴的别名时,例如。猛扑

alias tail='colortail -n 30'

您可以按别名类型检查输出的内容是否类似于tail isan alias of colortail -n 30。那么你有罪魁祸首:)

解:

用删除别名

unalias tail

确保通过此命令使用“真实”尾巴二进制文件

type tail

应该输出如下内容:

tail is /usr/bin/tail

然后您可以运行命令

tail -f foo.log |grep --line-buffered something

祝好运。


-4

如果没有行缓冲选项,请使用awk(另一个出色的bash实用程序)代替grep!它将持续从尾部流式传输您的数据。

这就是你使用grep的方式

tail -f <file> | grep pattern

这就是你使用awk的方式

tail -f <file> | awk '/pattern/{print $0}'

6
这是不正确的。与大多数其他标准Unix工具一样,Awk可以立即执行行缓冲。(此外,这{print $0}是多余的,因为在条件通过时,打印是默认操作。)
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.