如何“grep”一个连续的流?

是否可以在连续流上使用grep

我的意思是有点像tail -f <file>命令,但是输出上有grep,以便只保留我感兴趣的行。

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

411555 次浏览

我一直使用tail -f <file> | grep <pattern>

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

是的,这实际上可以很好地工作。Grep和大多数Unix命令一次对流进行一行操作。如果匹配,则会分析并传递从尾部出来的每一行。

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

tail -f file | stdbuf -o0 grep my_pattern

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

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

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

看起来不久前--line-buffered对GNU grep来说并不重要(几乎在任何Linux上使用),因为它默认刷新(YMMV用于其他Unix类如SmartOS、AIX或QNX)。然而,截至2020年11月,需要--line-buffered(至少在openSUSE中使用GNU grep 3.5,但根据下面的评论,似乎通常需要它)。

在你没有行缓冲选项的地方使用awk(另一个很棒的bash实用程序)而不是grep!它会不断地从尾巴流式传输你的数据。

这就是你如何使用grep

tail -f <file> | grep pattern

这就是你如何使用awk

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

在大多数情况下,你可以tail -f /var/log/some.log |grep foo,它会很好地工作。

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

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

你可以考虑这个答案作为增强…通常我使用

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

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

-A和-B用于在模式出现之前和之后获取线条…这些块将出现在虚线分隔符之间

但对我来说,我更喜欢做以下事情

tail -F <file> | less

如果你想在流式日志中搜索,这是非常有用的。我的意思是回顾和前进,深入观察

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

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

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

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

显然是一种粗俗主义:$BASHPID将是尾巴命令的进程ID。se命令紧随管道中的尾巴之后,因此se进程ID将是$BASHPID+1。

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

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

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

没有看到任何人提供我通常的选择:

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

我更喜欢这样,因为您可以使用ctrl + c随时停止并浏览文件,然后只需按shift + f即可返回实时流式搜索。

这个命令对我有用(Suse):

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

收集邮件服务的登录信息

你肯定不会成功

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

当你使用“彩色尾巴”作为尾巴的别名时,例如。在bash中

alias tail='colortail -n 30'

您可以查看类型别名如果这个输出类似尾巴是colortail -n 30的别名。然后你有你的罪魁祸首:)

解决方案:

删除别名

unalias tail

确保您使用此命令的“真正”尾二进制文件

type tail

它应该输出如下内容:

tail is /usr/bin/tail

然后你就可以运行你的命令了

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

祝你好运。

在这个问题上有点晚了,考虑到这种工作是监控工作的重要组成部分,这是我的(没那么短)答案…

使用跟踪日志

1.命令tail

这个命令比在已经发布的答案上读到的要少一些

  1. 遵循选项tail -ftail -F之间的区别,从manpage

       -f, --follow[={name|descriptor}]output appended data as the file grows;...-F     same as --follow=name --retry...--retrykeep trying to open a file if it is inaccessible

    这意味着:通过使用-F而不是-ftail将在删除时重新打开文件(对于示例,在日志轮换时)。
    这对于在许多天内查看日志文件很有用。

  2. 同时跟随不止一个文件的能力
    我已经用过了:

    tail -F /var/www/clients/client*/web*/log/{error,access}.log /var/log/{mail,auth}.log \/var/log/apache2/{,ssl_,other_vhosts_}access.log \/var/log/pure-ftpd/transfer.log

    通过数百个文件跟踪事件…(请考虑此答案的其余部分,以了解如何使其具有可读性…;)

  3. 使用开关-n(不要使用-c进行行缓冲!)。
    默认情况下tail将显示最后10行。这可以调整:

    tail -n 0 -F file

    将跟随文件,但只会打印新行

    tail -n +0 -F file

    将在跟随他的进展之前打印整个文件。

2.管道时的缓冲区问题:

如果您计划过滤ouptuts,请考虑缓冲!请参阅sed-u选项,grep--line-bufferedstdbuf命令:

tail -F /some/files | sed -une '/Regular Expression/p'

是(比使用grep更有效)比如果你不使用sed命令中的-u开关更具反应性。

tail -F /some/files |sed -une '/Regular Expression/p' |stdbuf -i0 -o0 tee /some/resultfile

3.最近的日记账系统

在最近的系统上,而不是tail -f /var/log/syslog,你必须以几乎相同的方式运行journalctl -xf

journalctl -axf | sed -une '/Regular Expression/p'

但是阅读man page,这个工具是为日志分析而构建的!

4.将其集成到脚本中

  1. 两个(或更多)文件的彩色输出

    这是一个脚本观察许多文件的示例,第一个文件的着色方式与其他文件不同:

    #!/bin/bash
    tail -F "$@" |sed -une "/^==> /{h;};//!{G;s/^\\(.*\\)\\n==>.*${1//\//\\\/}.*<==/\\o33[47m\\1\\o33[0m/;s/^\\(.*\\)\\n==> .* <==/\\o33[47;31m\\1\\o33[0m/;p;}"

    它们在我的主机上运行良好,运行:

    sudo ./myColoredTail /var/log/{kern.,sys}log
  2. 交互式脚本

    您可能正在查看日志以对事件做出反应?

    这是一个小脚本,当一些USB设备出现或消失时播放一些声音,但相同的脚本可以发送邮件或任何其他交互,例如打开咖啡机…

    #!/bin/bash
    exec {tailF}< <(tail -F /var/log/kern.log)tailPid=$!
    while :;doread -rsn 1 -t .3 keyboard[ "${keyboard,}" = "q" ] && breakif read -ru $tailF -t 0 _ ;thenread -ru $tailF linecase $line in*New\ USB\ device\ found* ) play /some/sound.ogg ;;*USB\ disconnect* ) play /some/othersound.ogg ;;esacprintf "\r%s\e[K" "$line"fidone
    echoexec {tailF}<&-kill $tailPid

    您可以按Q退出