0 grep logs pipe tail text-processing
我希望获取与测试字符串匹配的日志文件的最后一行并输出到另一个日志文件。
我需要测试许多不同的文本字符串,并根据输出发送到不同的日志文件。
我正在使用这个:
tail -f -n 1 input.log | grep string1 >>output1.log
Run Code Online (Sandbox Code Playgroud)
然后我想像这样重复测试:
tail -f -n 1 input.log | grep string2 >>output2.log
tail -f -n 1 input.log | grep string3 >>output3.log
Run Code Online (Sandbox Code Playgroud)
如何在单个高效的 bash 脚本中实现这一目标?
使用 awk 而不是 grep:
awk '/string1/ { print >> "output1.log" ; fflush() }
/string2/ { print >> "output2.log" ; fflush() }
/string3/ { print >> "output3.log" ; fflush() }' input.log
Run Code Online (Sandbox Code Playgroud)
这会将所有匹配的行输出到它们各自的 output.log 文件。那是因为我无法理解您的冲突tail -f
和tail -n 1
要求。如果您确实希望它input.log
从当前的最后一行开始,则通过管道tail -f -n 1
进入awk
脚本并去掉input.log
行尾的 。例如
tail -f -n 1 input.log | awk '...same awk script as above...'
Run Code Online (Sandbox Code Playgroud)
你也可以用tee
andgrep
和process 替换来做
(但它会明显变慢):
tee >(grep --line-buffered string1 >> output1.log) \
>(grep --line-buffered string2 >> output2.log) \
>(grep --line-buffered string3 >> output3.log) < input.log
Run Code Online (Sandbox Code Playgroud)
或者
tail -f -n 1 input.log | tee .....
Run Code Online (Sandbox Code Playgroud)
注:该fflush()
在awk
溶液中,并--line-buffered
在选项tee
的解决方案,如果你的管道输出只需要tail -f
(或其他一些永无止境的过程)插入awk
或tee
。
没有它们,输出文件只会在输出缓冲区(awk 或 grep)已满时写入 - 如果作业中止而缓冲区中有未写入的输出(例如通过按 Ctrl-C),则任何输出仍在缓冲区将丢失。
使用它们,这两种解决方案的运行速度都慢得多(因为它们在每次写入时都会刷新输出)——但这不太可能重要,除非输入文件非常大。
顺便说一句,当输入结束时,这不是问题 - 在这种情况下,awk 和 grep 在退出之前都会自动刷新它们的输出缓冲区。
另一种选择是在子 shell 中运行管道到awk
(或tee
),该子外壳捕获并忽略来自 Ctrl-C 的中断信号。例如
tail -f input.log | (
trap '' INT
awk '/string1/ { print >> "output1.log" }
/string2/ { print >> "output2.log" }
/string3/ { print >> "output3.log" }'
)
Run Code Online (Sandbox Code Playgroud)
在tail -f
按Ctrl-C的影响(杀死),但子shell中运行awk
忽略它。 awk
刷新其输出缓冲区并在tail
被杀死时退出,因为它的输入已完成。
有关另一个示例/说明,请参阅awk 脚本中的Trap Ctrl-C。
如果您不希望它跟随日志文件,则不要使用tail
's-f
选项。
只需使用tail -n 1 | .....
或查看 Guy 的答案,它将所有三个字符串的最后一个匹配项打印到各自的输出文件中。