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

awk:仅当特定行不存在时才过滤块,awk,filtering,Awk,Filtering,我得到一个文本流,看起来像这样: whatever => foo, arg => 'some text over multiple lines sometimes', bytes => 123, ... awk '/arg =>/{f=1} f; /bytes =>/{f=0}' file 我感兴趣的是arg=>和bytes=>之间的文本。所以我用滤纸过滤掉了这个区块 cat mystream | awk '/arg =>/,/bytes =&

我得到一个文本流,看起来像这样:

whatever => foo,
arg => 'some text
   over multiple lines
   sometimes',
bytes => 123,
...
awk '/arg =>/{f=1} f; /bytes =>/{f=0}' file
我感兴趣的是
arg=>
bytes=>
之间的文本。所以我用滤纸过滤掉了这个区块

cat mystream | awk '/arg =>/,/bytes =>/'
这很好用。但是现在,如果文本中有一个单词,我想跳过整个部分。类似于
grep-v
的东西,但是对于整个块,而不仅仅是行。有什么想法吗?谢谢


注意,这并不局限于awk,这只是我想到的。任何其他工具也可以。

awk'/arg=>/,/bytes=>/{s=s?s:NR;如果($0~/some/)退出;a[NR]=$0;e=NR;}END{for(i=s;i
awk'/arg=>/,/bytes=>/{s=s:NR;如果($0~/some/)退出;a[NR]=$0;e=NR;}END{for(i=s;i这里有一种方法可以用GNU来做:

awk '/arg =>/,/bytes =>/ {s=s?s:NR;if($0~/some/)exit; a[NR]=$0;e=NR;}END{for(i=s;i<=e;i++)print a[i]}' file
m1='arg =>'
m2='bytes =>'
pattern='some'
awk -v RS="$m1|$m2" -v start="$m1" -v end="$m2" -v pattern="$pattern" \
  'RT == end && $0 !~ pattern { print start $0 end }' < mystream
m1='arg=>'
m2='bytes=>'
花样
awk-v RS=“$m1 |$m2”-v start=“$m1”-v end=“$m2”-v pattern=“$pattern”\
'RT==end&&$0!~pattern{print start$0 end}'
也就是说,在开始标记和结束标记处分割流,然后,当找到结束标记且块不包含
$pattern
时,打印它


请注意,
m1
m2
pattern
都是正则表达式,因此可以根据您的需要进行调整。还要注意,如果您的输入块包含
m1
m2
,这将不起作用。另请参见下面的Ed注释。

使用GNU awk可以实现这一点:

m1='arg =>'
m2='bytes =>'
pattern='some'
awk -v RS="$m1|$m2" -v start="$m1" -v end="$m2" -v pattern="$pattern" \
  'RT == end && $0 !~ pattern { print start $0 end }' < mystream
m1='arg=>'
m2='bytes=>'
花样
awk-v RS=“$m1 |$m2”-v start=“$m1”-v end=“$m2”-v pattern=“$pattern”\
'RT==end&&$0!~pattern{print start$0 end}'
也就是说,在开始标记和结束标记处分割流,然后,当找到结束标记且块不包含
$pattern
时,打印它


请注意,
m1
m2
pattern
都是正则表达式,因此可以根据您的需要进行调整。另外请注意,如果您的输入块包含
m1
m2
,这将不起作用。另请参见下面的Ed注释。

使用/pat1/,/pat2/范围通常看起来是个好主意,但随后也一样n当你需要添加一个条件或做其他事情时,它会变得平淡。我想你最好使用这样的标志:

whatever => foo,
arg => 'some text
   over multiple lines
   sometimes',
bytes => 123,
...
awk '/arg =>/{f=1} f; /bytes =>/{f=0}' file
因为这可以扩展,而无需全部重新写入。在这种情况下,只要在范围内(即设置“f”时)建立一条记录,并在适当的情况下在范围结束时打印它。这将始终打印它:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f) printf "%s",rec; f=0}' file
只有在记录中出现文本“whatever”时,才会打印:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec ~ "whatever")) printf "%s",rec; f=0}' file
awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec !~ "whatever")) printf "%s",rec; f=0}' file
只有在记录中没有出现文本“whatever”时,才会打印:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec ~ "whatever")) printf "%s",rec; f=0}' file
awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec !~ "whatever")) printf "%s",rec; f=0}' file
这是您下面评论中的脚本(稍微重新格式化)

|
awk'
/arg=>/{rec=”“;f=1}
f{rec=rec$0 ORS}
/字节=>/{
if(rec!~/menuStructure | session/)
打印文件“%s”,记录
f=0
}
“| sed”s/*字节=>./\n------\n/g“| sed”s/arg=>//g”
基于此,我认为此脚本将完成您尝试执行的操作:

<tcpdump> |
awk '
   /bytes =>/ {
      if (f && (rec !~ /menuStructure|session/))
         print rec "----------"
      f=0
   }
   f {rec = rec $0 ORS}
   sub(/arg =>/,"") {rec=$0; f=1}
'
|
awk'
/字节=>/{
if(f&(rec!~/menuStructure | session/)
打印记录“------------”
f=0
}
f{rec=rec$0 ORS}
sub(/arg=>/,“”){rec=$0;f=1}
'

使用/pat1/、/pat2/范围通常看起来是个好主意,但一旦你需要添加条件或做其他事情,它就会变得平淡。我想你最好使用这样的标志:

whatever => foo,
arg => 'some text
   over multiple lines
   sometimes',
bytes => 123,
...
awk '/arg =>/{f=1} f; /bytes =>/{f=0}' file
因为这可以扩展,而无需全部重新写入。在这种情况下,只要在范围内(即设置“f”时)建立一条记录,并在适当的情况下在范围结束时打印它。这将始终打印它:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f) printf "%s",rec; f=0}' file
只有在记录中出现文本“whatever”时,才会打印:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec ~ "whatever")) printf "%s",rec; f=0}' file
awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec !~ "whatever")) printf "%s",rec; f=0}' file
只有在记录中没有出现文本“whatever”时,才会打印:

awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec ~ "whatever")) printf "%s",rec; f=0}' file
awk '/arg =>/{rec=""; f=1} f{rec = rec $0 ORS} /bytes =>/{ if (f && (rec !~ "whatever")) printf "%s",rec; f=0}' file
这是您下面评论中的脚本(稍微重新格式化)

|
awk'
/arg=>/{rec=”“;f=1}
f{rec=rec$0 ORS}
/字节=>/{
if(rec!~/menuStructure | session/)
打印文件“%s”,记录
f=0
}
“| sed”s/*字节=>./\n------\n/g“| sed”s/arg=>//g”
基于此,我认为此脚本将完成您尝试执行的操作:

<tcpdump> |
awk '
   /bytes =>/ {
      if (f && (rec !~ /menuStructure|session/))
         print rec "----------"
      f=0
   }
   f {rec = rec $0 ORS}
   sub(/arg =>/,"") {rec=$0; f=1}
'
|
awk'
/字节=>/{
if(f&(rec!~/menuStructure | session/)
打印记录“------------”
f=0
}
f{rec=rec$0 ORS}
sub(/arg=>/,“”){rec=$0;f=1}
'

正常工作,但是抛出了一个
捕获的SIGPIPE
错误。谢谢你的努力,但我只能在没有发生的情况下接受它。正常工作,但是抛出了一个
捕获的SIGPIPE
错误。谢谢你的努力,但我只能在没有发生的情况下接受它。你需要锚定你的RS,否则如果它出现在st以外的地方,它将失败行的艺术。OP还希望打印包含
字节=>
的整行,而不仅仅是文本
字节=>
,因此您需要使RS包含类似
字节=>..\n
的内容,然后在匹配上打印RT而不是
end
。您需要锚定RS,否则如果它出现在其他地方,它将失败一行的开头。OP还希望打印出包含
字节=>
的整行,而不仅仅是文本
字节=>
,因此您需要让RS包含类似
字节=>.\n
的内容,然后在匹配中打印RT而不是
end
。@tombom不客气。我只是更新了它来处理cas在输入文件中,结束模式可以在随后的开始模式之前出现两次。另一个问题,我现在正在尝试执行以下操作:
awk'/arg=>/{rec=“”;f=1}f{rec=rec$0 ORS};/bytes=>/{if(rec!~“menustrustructure”&&rec!~“session”)printf“%s”,rec;f=0}'.\sed“s/*bytes=>.*.\n------\n/g“| sed”s/arg
基本上,只是添加了另一个管道。但是它什么也不打印。如果没有我的添加,它会打印。为什么?你没有给它一个文件来读取?无论你想做什么,它都可以打印