这是我的要求。
我正在跟踪一个日志文件并对其进行 grep。
我想获取每个 grep 结果的一些上下文。
但上下文应该是“直到匹配模式”而不是行数(这是grep -A/-B/-C
提供的)。
例如
说这是我的日志..
[l]
是每个日志行的前缀。另外还会有[logTypeA]
or的前缀[logTypeB]
[l][logTypeA] - Log line 1
[l][logTypeB] - Log line 2
[l][logTypeA] - Log line 3
....
Random data about Log line 3
....
[l][logTypeB] - Log line 4
现在,如果我的tail
命令是tail -f log_file.log | grep "[logTypeA]"
,我会得到一个输出
[l][logTypeA] - Log line 1
[l][logTypeA] - Log line 3
但我需要 grep 结果的上下文信息,并且该上下文不是某些行数,而是直到匹配特定模式(在本例中为 [l])。
在这个例子中我希望我的 grep 结果是
[l][logTypeA] - Log line 1
[l][logTypeA] - Log line 3
....
Random data about Log line 3
....
从这里 (如何在每个 grep 匹配之后显示行,直到其他特定匹配?),我尝试了类似的sed
命令tail
tail -f log_file.log | sed '/\[logTypeA\]/,/\[l\]/p'
但这似乎不起作用。
有任何想法吗?
答案1
这是 Awk 中极其常见的模式。将相关行收集到“记录”中,收集完所有记录后,如果符合特定条件,则打印记录。
tail -f file |
awk '/\[l]/ { if (p && stored) print stored; stored = ""; p=0 }
/\[logTypeA]/ { p=1 }
{ stored = stored (stored ? ORS : "") $0 }
END { if (p) print stored }'
END
对于永无止境的流,该条件实际上没有意义tail -f
,但我将其包含在内是为了更好地衡量,并避免当您要测试的最后一条记录应该被打印时,避免令人讨厌的测试失败,但不会没有该END
子句。
答案2
我最终可能会用 Perl 语句来做这件事。您可以在 sed 中完成此操作,但感觉它开始遇到 sed 的“无意的图灵完整性”部分。
Perl 一行(perl -ne
这才是真正的要点)
echo '[l] boring\nboring data\n[l] boring\n[l]interesting\ndata\ndata\n[l]boring' | perl -ne '
if (/\[l\].*interesting/ ) { print $_; $collect=1 ; }
elsif (/\[l\]/) {$collect=0 }
elsif ($collect) {print $_}'
作为参考,这是执行相同操作的 sed 单行代码。 (使用的sed的特点:乙来实现切换,时间来实现条件执行)。
echo '[l] boring\nboring data\n[l] boring\n[l\]interesting\ndata\ndata\n[l]boring' | sed -nE '/\[l\].*interesting/ {
p;
s/.*/collect/ ; x ; # store collect marker in the pattern space
b; # terminate processing
}
/\[l\]/ {
s/.*// ; x; # clear hold flag
b
}
/./ {
x;
s/collect/collect/;
T; x; p # print if we are collecting
}
'