awk:仅当特定行不存在时才过滤块

fan*_*nts 1 awk filtering

我有一个看起来像这样的文本流:

whatever => foo,
arg => 'some text
   over multiple lines
   sometimes',
bytes => 123,
...
Run Code Online (Sandbox Code Playgroud)

我很感兴趣之间的文字arg =>bytes =>.所以我过滤掉了块

cat mystream | awk '/arg =>/,/bytes =>/'
Run Code Online (Sandbox Code Playgroud)

哪个工作正常.但是现在我想跳过整个块,如果文本中有一个单词的话.喜欢的东西grep -v,但对于整个块,而不仅仅是线.有任何想法吗?谢谢.

请注意,这不仅限于awk,它只是我想到的.任何其他工具也没问题.

Ed *_*ton 6

使用/ pat1 /,/ pat2 /范围通常看起来是一个好主意但是只要你需要添加一个条件或做其他事情它就会失败.恕我直言你最好只使用这样的标志:

awk '/arg =>/{f=1} f; /bytes =>/{f=0}' file
Run Code Online (Sandbox Code Playgroud)

因为这可以在没有完全重写的情况下进行扩展.在这种情况下,只需在您处于范围内时(即设置"f"时)构建记录,并在范围结束时根据需要进行打印.这将始终打印出来:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f) printf "%s",rec; f=0}' file
Run Code Online (Sandbox Code Playgroud)

只有当记录中出现"what"字样时才会打印出来:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec ~ "whatever")) printf "%s",rec; f=0}' file
Run Code Online (Sandbox Code Playgroud)

只有当记录中没有出现"what"字样时,才会打印出来:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec !~ "whatever")) printf "%s",rec; f=0}' file
Run Code Online (Sandbox Code Playgroud)

这是您在下面的评论中的脚本(稍微重新格式化)

<tcpdump> |
awk '
   /arg =>/ {rec=""; f=1}
   f {rec = rec $0 ORS}
   /bytes =>/ {
      if (rec !~ /menuStructure|session/)
         printf "%s",rec
      f=0
   }
' | sed "s/.*bytes =>.*/\n----------\n/g" | sed "s/arg => //g"
Run Code Online (Sandbox Code Playgroud)

基于此,我认为这个脚本会做你想做的事情:

<tcpdump> |
awk '
   /bytes =>/ {
      if (f && (rec !~ /menuStructure|session/))
         print rec "----------"
      f=0
   }
   f {rec = rec $0 ORS}
   sub(/arg =>/,"") {rec=$0; f=1}
'
Run Code Online (Sandbox Code Playgroud)