sed - 如果一行与条件匹配,则打印与模式范围匹配的行

sed - 如果一行与条件匹配,则打印与模式范围匹配的行

我有一个需要处理的多行日志条目格式。

日志看起来像这样:

--START--
Device=B
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=B
Data=asdfasdf
--END--
--START--
Device=A
Data=asdfasdf
--END--
--START--
Device=B
Data=asdfasdf
--END--
--START--
Device=C
Data=asdfasdf
Lorem=Ipsum
--END--

我想打印--START--和之间的所有内容(--END--如果特定模式匹配)。

例如:

打印所有条目Device=A

--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
--END--

到目前为止我所能做的就是写:

sed -e -n '/--START--/,/--END--/p' < input

它有效地打印输入,但我认为我需要添加{}到过滤器N,然后在条件匹配时打印。

我也觉得我完全迷失了。

如果单行匹配条件,您知道如何打印多行吗?

答案1

$ sed -n '/--START--/{:a;N;/--END--/!ba; /Device=A/p}' file
--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
--END--

(上面是在 GNU sed 上测试的。它必须经过调整才能在 BSD/OSX 上运行。)

怎么运行的:

  • /--START--/{...}

    每次到达包含 的行时--START--,就运行大括号内的命令{...}

  • :a

    定义一个标签a

  • N

    读取下一行并将其添加到模式空间。

  • /--END--/!ba

    除非模式空间现在包含--END--,否则跳回 label a

  • /Device=A/p

    如果我们到达这里,这意味着模式空间以 开始--START--并以 结束--END--。另外,如果模式空间包含Device=A,则打印 ( p) 它。

答案2

sed使用保留空间的其他变体

sed 'H              #add line to hold space
     /--START--/h   #put START into hold space (substitute holded in)
     /--END--/!d    #clean pattern space (start next line) if not END
     x              #put hold space into pattern space
     /Device=A/!d   #clean pattern space if it have not "Device=A"
    ' file

答案3

sed

$ -e:1 -e'$!N;/--END--/{
  /Device=A/!d
  b
}' -eb1 <file
--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
--END--

--START--这会将之间和之间的所有行读取--END--到模式空间中。如果匹配--END--,我们检查模式空间是否不包含Device=A,将其删除,否则sed打印模式空间然后开始下一个循环。

awk

awk '
  /--START--/ {
    getline d
    if (d ~ /Device=A/) {
      p = 1
      printf "%s\n%s\n", $0, d
      next
     }
  }
  p
  /--END--/ { p = 0 }
' <file

答案4

这里已经有其他几个很好的答案,它们演示了如何测试之间的字符串--START----END--块,但是,考虑到您的示例输入,您可能不需要真正担心--START--根本不。

sed -n '$!N;/^Device=A\n/,/\n--END--/P;D'

...将打印所有内容Device=A\n直到下一个发生之前发生的最后一个ewline--END--在每个块中。不用担心--START--因为它似乎没有必要检查它。

所以对于像这样的块:

--START--
Device=A
...stuff...
--END--

...输出将是...

Device=A
...stuff...

...但是对于像这样的块...

--START--
Device=B
Device=A
...stuff...
--END--

...它会输出相同的结果。

它的工作原理是将 ext 输入行附加到不是最后N一行的每一行,因此模式空间如下所示:!$

^line1\nline2$

对于序列之间出现的每个模式空间^Device=A\n\n--END--当前模式中的两行中的第一行被P打印,然后D删除,然后用剩余的内容开始下一个循环。所以下一个模式空间看起来像......

^line2\nline3$

相关内容