是否可以在连续流上使用 grep
呢?
我的意思是类似于 tail -f <file>
命令,但是将 grep
应用于输出结果,以便只保留我感兴趣的行。
我尝试过 tail -f <file> | grep pattern
,但似乎 grep
只能在 tail
结束后执行,也就是说永远不会执行。
在使用BSD grep(FreeBSD,Mac OS X 等)时,打开 grep
的行缓冲模式。
tail -f file | grep --line-buffered my_pattern
看起来之前在GNU grep(在几乎所有Linux上使用)中,--line-buffered
并不重要,因为它默认会刷新(对于其他类Unix系统如SmartOS、AIX或QNX可能有所不同)。然而,从2020年11月起,--line-buffered
是必需的(至少在openSUSE中使用GNU grep 3.5时是这样的,但根据下面的评论似乎通常需要这样做)。
strace
的输出。如果没有使用 --line-buffered
,它将无法正常工作。 - sjas--line-buffered
参数就得不到输出。不过经过测试,发现GNU grep会按照您所描述的方式运行。因此,与Unix的大多数事情一样,它取决于您所使用的平台实现。由于问题没有指定平台,因此您提供的信息似乎是错误的 - 经过对比BSD grep和GNU grep的代码后,行为显然受--line-buffered
选项控制。只是默认情况下只有GNU grep会刷新输出。 - Richard Waite我经常使用 tail -f <文件名> | grep <匹配模式>
命令。
它会等待 grep 刷新,而不是等待它执行完(我使用的是 Ubuntu 操作系统)。
我认为你的问题是grep使用了一些输出缓冲。尝试
tail -f file | stdbuf -o0 grep my_pattern
它将把grep的输出缓冲模式设置为无缓冲。
grep
命令之外,还可以用于许多其他命令。 - Peter V. Mørchtop
命令使用stdbuf和unbuffer命令)。并且真的没有“神奇”的解决方案:unbuffer 有时也会失败,例如 awk 使用不同的缓冲实现(stdbuf 也会失败)。 - XzKtostdbuf
、unbuffer
和stdio缓冲的更多信息,请访问http://www.pixelbeat.org/programming/stdio_buffering/。 - Tor Klingberg如果您想在整个文件中查找匹配项(而不仅仅是尾部),并且希望它等待任何新匹配项,那么这个方法很好用:
tail -c +0 -f <file> | grep --line-buffered <pattern>
使用-c +0
选项,表示输出应该从文件的开头(+
)开始0
字节(-c
)。
tail -f /var/log/some.log | grep foo
并且它将正常工作。--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
如果您想在流日志中搜索,这将非常有用。我是说可以向前和向后查看并深入查看。
grep -C 3 <pattern>
取代了 -A <N>
和 -B <N>
的功能。这个命令会显示匹配 <pattern>
的行,并显示前后三行。 - AKS我平常处理这种情况时,没有看到有人提供我的首选方法:
less +F <file>
ctrl + c
/<search term>
<enter>
shift + f
我更喜欢这种方式,因为你可以使用 ctrl + c
在任何时候停止和导航文件,然后只需按下 shift + f
返回到实时流搜索。
tail
这个命令比已经发布过的答案更强大。
Difference between follow option tail -f
and tail -F
, from manpage:
-f, --follow[={name|descriptor}]
output appended data as the file grows;
...
-F same as --follow=name --retry
...
--retry
keep trying to open a file if it is inaccessible
This mean: by using -F
instead of -f
, tail
will re-open file(s) when removed (on log rotation, for sample).
This is usefull for watching logfile over many days.
Ability of following more than one file simultaneously
I've already used:
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
For following events through hundreds of files... (consider rest of this answer to understand how to make it readable... ;)
Using switches -n
(Don't use -c
for line buffering!).
By default tail
will show 10 last lines. This can be tunned:
tail -n 0 -F file
Will follow file, but only new lines will be printed
tail -n +0 -F file
Will print whole file before following his progression.
如果您计划过滤输出,请考虑缓冲!请参阅sed
的-u
选项,grep
的--line-buffered
选项或stdbuf
命令:
tail -F /some/files | sed -une '/Regular Expression/p'
grep
更有效)”比不使用更加反应灵敏。tail -F /some/files |
sed -une '/Regular Expression/p' |
stdbuf -i0 -o0 tee /some/resultfile
在最近的系统中,您需要运行journalctl -xf
而不是tail -f /var/log/syslog
,方式几乎相同...
journalctl -axf | sed -une '/Regular Expression/p'
Colored output of two files (or more)
Here is a sample of script watching for many files, coloring ouptut differently for 1st file than others:
#!/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;}"
They work fine on my host, running:
sudo ./myColoredTail /var/log/{kern.,sys}log
Interactive script
You may be watching logs for reacting on events?
Here is a little script playing some sound when some USB device appear or disappear, but same script could send mail, or any other interaction, like powering on coffe machine...
#!/bin/bash
exec {tailF}< <(tail -F /var/log/kern.log)
tailPid=$!
while :;do
read -rsn 1 -t .3 keyboard
[ "${keyboard,}" = "q" ] && break
if read -ru $tailF -t 0 _ ;then
read -ru $tailF line
case $line in
*New\ USB\ device\ found* ) play /some/sound.ogg ;;
*USB\ disconnect* ) play /some/othersound.ogg ;;
esac
printf "\r%s\e[K" "$line"
fi
done
echo
exec {tailF}<&-
kill $tailPid
You could quit by pressing Q key.
sed是一个更好的选择(流编辑器)
tail -n0 -f <file> | sed -n '/搜索字符串/p'
如果您想要在找到特定字符串后退出tail命令:
tail --pid=$(($BASHPID+1)) -n0 -f <file> | sed -n '/搜索字符串/{p; q}'
显然这是一个bashism: $BASHPID将是tail命令的进程id。 sed命令紧随tail在管道中,所以sed的进程id将是$BASHPID+1。
$BASHPID+1
)将是您自己的进程是错误的,并且这对于解决缓冲问题毫无作用,这可能是OP想要询问的问题。特别是,在这里推荐使用sed
而不是grep
似乎只是一种(可疑的)个人喜好。(如果您试图传达的是p;q
行为,则可以通过grep -m 1
实现。) - tripleee是的,这实际上完全可行。 Grep
和大多数 Unix 命令逐行处理流。每一行从 tail 中输出的行都将被分析并在匹配时传递。
grep
是管道链中的最后一条命令,那么它会按照你所说的那样执行。然而,如果它在中间位置,它会每次缓冲大约8k的输出。 - Mahmoud Al-Qudsi
tail -f file
可以工作(我可以实时看到新的输出)。 - Matthieu Napoli