Grep/awk/sed 有状态线路匹配

Grep/awk/sed stateful line matching

我有一个日志文件,其中包含的条目本身可以分为多行,我想找到这些条目的所有实例。

例如:

AAA normal line
BBB normal line
XXX important line
 important line continuation 1
 important line continuation 2
BBB normal line
 normal line continuation 1
AAA normal line
XXX important line
 important line continuation 1
 important line continuation 2
 important line continuation 3
AAA normal line

所有条目均以代码开头(AAA、BBB、XXX 等)。以代码 XXX 开头的行及其关联的续行是我感兴趣的行。续行以 space 开头,并且可以有任意数量的续行。续行之后的行可以任何代码开头。

我认为这是一种 'stateful' 匹配(虽然它可能无法通过这种方式解决)...即:我想要匹配模式 XXX 的行,然后所有紧接着以 [= 开头的行=28=](直到他们不这样做)。

我如何在拖尾日志文件的同时为此使用 grep、sed 或 awk?

更新: 示例期望结果:

XXX important line
 important line continuation 1
 important line continuation 2
XXX important line
 important line continuation 1
 important line continuation 2
 important line continuation 3

这个 awk 应该有效:

awk '/^[^ \t]/{p = ( == "XXX")} p' file

XXX important line
 important line continuation 1
 important line continuation 2
XXX important line
 important line continuation 1
 important line continuation 2
 important line continuation 3

命令说明:

  • /^[^ \t]/:条件,如果一行不是以space或制表符
  • 开头
  • {: 启动动作块
  • p = ( == "XXX"):如果第一列是 XXX,则将 p 设置为 1,否则将其设置为 0
  • }: 结束块
  • p:如果p==1则打印行
当我们找到 == XXX 时,

p 将被设置为 1,并且我们将继续打印行,直到 p 再次变为 0

这可能适合您 (GNU sed):

sed '/^XXX/{:a;n;/^ /ba};d' file

如果一行以 XXX 开头,打印它然后获取下一行。

如果该行以 space 开头,打印它并获取下一行并重复。

将删除任何其他行。

N.B。 n 通常打印模式 space 中的当前行,然后用下一行替换它。这是 sed 中的正常循环,例如sed '' file 将只打印文件。如果使用 -n 选项,则不执行隐式打印,因此:

sed -n '/^XXX/{:a;p;n;/^ /ba}' file

实现相同的结果。

如果行的开头可能是制表符或任何白色 space,请使用:

sed '/^XXX/{:a;n;/^\s/ba};d' file