是否可以在连续流中使用grep?
我的意思是一种tail -f 命令,但是输出上有grep,以便只保留我感兴趣的行。
我试过tail -f | grep pattern,但似乎grep只有在tail完成后才能执行,也就是说永远不能执行。
- 很可能生成文件的程序没有刷新其输出。
- tail -f file工作(我实时看到新的输出)
- 适用于unix.stackexchange.com
- @卢克真的没想到
- 输入流中可能没有新行?如果是这样,grep将不继续。
- 这是一个常见问题解答:mywiki.wooledge.org/bashfaq/009
- 呵呵,在管道里缓冲!也许这些答案对在这里搜索这个话题的人有帮助。
- @林奇,我遇到了你提到的问题,当grep从一个超慢(sleep infinity)蒸熟的原木,而我greed的字符串正好在sleep命令之前,因此没有新行被流,它永远不会退出。你能给点提示吗?
- @psyduck如果我理解正确的话,问题是缓冲区永远不会被冲到你的箱子里。我没有测试它,但可能是unbuffer可以帮助:linux.die.net/man/1/unbuffer
使用bsd grep(freebsd、mac os x等)时,打开Grep的线路缓冲模式。
1
| tail -f file | grep --line-buffered my_pattern |
对于GNUgrep(几乎在任何Linux上都使用),您不需要这样做,因为它在默认情况下都会刷新(对于其他UNIX,如smartos、aix或qnx,使用ymmv)。
- 如果在运行日志文件时跟踪一个被旋转的日志文件,会发生什么?logrotate是否能够旋转文件?
- @michaelniemand你可以使用tail-f文件grep——行缓冲我的模式
- 一定要拿出你平时不喜欢的旗帜-R(其他笨蛋用的)
- @迈克尔戈德施泰恩放轻松。人们对它投赞成票,因为当他们谷歌"grep-line-buffered"时,他们会发现这个页面,它为他们解决了一个问题,而这个问题可能不是问题所在。
- @在某些情况下似乎是真的。例如,我正在自动ssh会话中远程执行该命令(在参数中指定该命令)。你有更完整的解释吗?谢谢!
- @Michaelgoldshteyn-我怀疑这里的问题是,人们通过自己运行命令来确认它提供了正确的输出,然后对它进行上表决,而没有意识到"-line buffered"部分是完全多余的。
- 我来这里是为了增加strace的产量。如果没有--line-buffered,它将无法工作。
- @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仅由参数分析器设置。
- 我不认为--line bufferred是默认选项,至少在ssh连接上不是。我一直有这个问题,从来没有新的关于---线路缓冲直到今天…工作很棒!
- @Michaelgoldshteyn我在使用BSD grep的MacOS上,没有--line-buffered,我没有输出。然而,在测试之后,看起来GNUgrep像您描述的那样做。所以和大多数Unix一样,它依赖于平台的实现。由于问题没有指定平台,因此您的信息似乎是错误的——在检查了bsd grep的代码并将其与gnu grep进行比较之后,行为绝对由--line buffered选项控制。只是默认情况下只有gnu grep刷新。
我一直使用tail -f | grep 。
它将等到grep刷新,而不是等到它完成(我正在使用Ubuntu)。
- 这会持续很长一段时间,所以尽量不要不耐烦。
- 大约要多长时间?
- @Matthieu:主要取决于你擅长什么,以及你的操作系统上的缓冲区有多大。如果grep每隔几个小时只匹配一个短字符串,那么它将是第一次刷新前的几天。
- tail不使用输出缓冲-grep使用。
- 不,当输出到tty设备时,grep不进行输出缓冲,因为它显然在这个答案中。它做线路缓冲!这是正确的答案,应该是公认的答案。有关详细信息,请参阅我对当前接受(错误)答案的较长评论。
- 这就是在Windows上的GitBash中为我工作的解决方案。(删除了我下面的类似答案,其中包括可选的用于grep的-,不需要。)
- @Michaelgoldshteyn在回答你的长答案时多次指出,你的信息只适用于GNU grep,而不是BSD或其他实现,所以你能检查你的攻击性和公鸡确定性吗?
我认为您的问题是grep使用了一些输出缓冲。尝试
1
| tail -f file | stdbuf -o0 grep my_pattern |
将GREP的输出缓冲模式设置为无缓冲。
- 它的优点是除了grep之外,还可以用于其他许多命令。
- 然而,正如我在更多地使用它之后发现的那样,一些命令只有在连接到tty时才会刷新它们的输出,因此,unbuffer(在debian上的expect-dev包中)是国王。所以我会在stdbuf上使用unbuffer。
- @Peter V.M&248;rch是的,你是对的,Unbuffer有时可以在Stdbuf不能工作的地方工作。但我认为你正在尝试找到一个"魔法"程序,它总是能解决你的问题,而不是理解你的问题。创建虚拟tty与任务无关。stdbuf完全按照我们想要的做(将标准输出缓冲区设置为给定值),而unbuffer做了许多我们可能不想要的隐藏内容(将interactive top与stdbuf和unbuffer进行比较)。实际上没有"神奇"的解决方案:unbuffer有时也会失败,例如awk使用不同的缓冲区实现(stdbuf也会失败)。
- "但我认为你正试图找到一个"魔法"程序,它总是能解决你的问题,而不是理解你的问题。"—我认为你是对的!;-)
- 关于stdbuf、`unbuffer和stdio buffering的更多信息,请访问pixelbeat.org/programming/stdio_buffering。
在大多数情况下,您可以使用cx1(3),它将工作得很好。
如果需要在运行日志文件上使用多个grep,并且发现没有输出,则可能需要将--line-buffered开关插入中间grep,如下所示:
1
| tail -f /var/log/some.log | grep --line-buffered foo | grep bar |
如果您想在整个文件中找到匹配项(不仅仅是尾部),并且想让它静坐等待任何新的匹配项,那么这很好地工作:
1
| tail -c +0 -f <file> | grep --line-buffered <pattern> |
-c +0标志表示,输出应该从文件的开始(+开始)开始(-c字节)。
没看到有人像我一样主动提出:
1 2 3 4 5
| less +F <file>
ctrl + c
/<search term>
<enter>
shift + f |
我更喜欢这样,因为你可以随时使用ctrl + c来停止和浏览文件,然后点击shift + f返回到实时的流式搜索。
SED将是更好的选择(流编辑器)
tail -n0 -f | sed -n '/search string/p'
然后,如果希望在找到特定字符串后退出tail命令:
tail --pid=$(($BASHPID+1)) -n0 -f | sed -n '/search string/{p; q}'
显然是bashism:$bashpid是tail命令的进程ID。sed命令位于管道尾部之后,因此sed进程ID将为$bashpid+1。
- 假设系统上启动的下一个进程($BASHPID+1将是您的进程)在许多情况下都是错误的,这对于解决缓冲问题没有任何帮助,而缓冲问题可能正是操作人员试图询问的问题。特别是,在这里推荐sed而不是grep,似乎只是(可疑的)偏好问题。(如果你正试图做到这一点,那么你可以得到p;q与grep -m 1的行为。)
- 工作时,sed命令一准备好就打印每一行,而grep命令和--line-buffered没有打印。我真的不明白负1。
- 到目前为止,已经确定缓冲是GREP的问题。使用sed处理行缓冲不需要特殊操作,这是默认行为,因此我强调了字流。的确,不能保证$bashpid+1是要遵循的正确pid,但是由于pid分配是连续的,并且piped命令紧跟着被分配了一个pid,所以这是完全可能的。
您可以将此答案视为增强。通常我用
1
| tail -F <fileName> | grep --line-buffered <pattern> -A 3 -B 5 |
-如果文件旋转,f更好(如果文件旋转,f将无法正常工作)
-A和-B对于在图案出现之前和之后获取线条很有用。这些块将出现在虚线分隔符之间
- grep -C 3 ,如果n相同,则替换-a和-b。
这个命令对我有效(suse):
1
| mail-srv:/var/log # tail -f /var/log/mail.info |grep --line-buffered LOGIN >> logins_to_mail |
正在收集登录到邮件服务
是的,这真的很管用。Grep和大多数unix命令一次只能在一行上操作流。从尾部出来的每一行都将被分析,如果匹配的话,将被传递。
- 这实际上不正确。如果grep是管道链中的最后一个命令,它将按照您的解释执行。但是,如果它在中间,它将一次缓冲大约8K的输出。
使用awk(另一个很棒的bash实用程序)而不是grep,因为您没有行缓冲选项!它会不断地从尾部传输数据。
这就是你如何使用grep
1
| tail -f <file> | grep pattern |
这就是你用锥子的方法
1
| tail -f <file> | awk '/pattern/{print $0}' |
- 这是不正确的;awk-out-of-the-box执行行缓冲,就像大多数其他标准的Unix工具一样。(此外,{print $0}是冗余的,因为当条件通过时,打印是默认操作。)