【问题标题】:Grep/awk/sed stateful line matchinggrep/awk/sed 有状态行匹配
【发布时间】:2020-08-24 12:27:25
【问题描述】:

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

例如:

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 开头的行及其相关的续行是我感兴趣的行。续行以空格开头,并且可以有任意数量的续行。续行之后的行可以以任何代码开头。

我认为这是一种“有状态”匹配(尽管它可能无法通过这种方式解决)......即:我想要匹配模式 XXX 的行,然后所有紧跟在以空格开头的行(直到它们不匹配) 't)。

在跟踪日志文件的同时,如何 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

【问题讨论】:

  • 预期输出是什么?同时展示你的尝试。
  • 使用 sed 或 grep 非常简单(也可能使用 awk,我不擅长使用 awk)。想一想:你想要所有以“XXX”或“”开头的行。
  • @Beta 不,我不知道。例如,我不希望 BBB 线之后的延续线。
  • 对不起,我的错误。在 sed 中它仍然不是太糟糕,但您应该尝试一些解决方案。
  • @anubhava 更新为预期输出。我不知道 sed 或 awk,所以不知道他们是否有能力解决这个问题。我不知道用 grep 解决这个问题。

标签: awk sed grep stateful


【解决方案1】:

这个awk 应该可以工作:

awk '/^[^ \t]/{p = ($1 == "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]/: 条件,如果一行不以空格或制表符开头
  • {:启动动作块
  • p = ($1 == "XXX"):如果第一列为XXX,则将p设置为1,否则设置为0
  • }:结束块
  • p: 如果p==1 则打印行

当我们找到$1 == XXX 时,p 将被设置为1,并且我们将继续打印行,直到p 再次变为0

【讨论】:

  • 谢谢,但这是如何工作的?将其从语法反转到 awk 用户指南的部分是很困难的......看起来你有一个正则表达式用于“以空格或制表符以外的东西开头的行”,然后应用一个动作说“输出行第一个字段等于“XXX””。这如何捕获以下延续线? (同样,不知道 awk 使这很难理解,感谢您的帮助)。
  • 在答案中添加了解释。
  • “p: If p==1 then print line”的最终见解让我明白了。谢谢!不错的解决方案!
【解决方案2】:

这可能对你有用(GNU sed):

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

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

如果该行以空格开头,则打印它并获取下一个并重复。

任何其他行都将被删除。

注意n 通常打印模式空间中的当前行,然后用下一行替换它。这是 sed 中的正常循环,例如sed '' file 只会打印文件。如果使用-n 选项,则不会进行隐式打印,因此:

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

获得相同的结果。

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

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

【讨论】:

  • 是的,可以在 linux 上运行,谢谢! (不是在 Mac 上,但它似乎没有使用 GNU sed,正如您所指出的;sed: 1: "/^XXX/{:a;n;/^ /ba};d": unexpected EOF (pending }'s))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
相关资源
最近更新 更多