使用sed或awk在两个正则表达式之间选择文件的块打印部分

时间:2015-04-10 08:49:09

标签: bash awk sed

sed -n '/pattern1/,/pattern2/p'

pattern1   
a   
b   
pattern2   
cd   
pattern1   
ef    
pattern2    
gh    
pattern1     
ef     
pattern2     

这将在所有匹配的pattern1和pattern2之间生成输出

但是我如何选择打印哪个块只打印最后一个匹配的模式块或仅打印第一个匹配的模式块?

3 个答案:

答案 0 :(得分:2)

打印第N次出现

以下是使用awk的一种方法:

$ awk '/pattern1/{++f;p=1}p&&f==2;/pattern2/{p=0}' file
pattern1
ef
pattern2

中间的数字2控制打印的事件(在本例中为第二个)。

解释

当打开模式匹配时,f递增,并设置p标志。匹配结束模式时,p标志未设置。只有在p标志设置且f具有特定值时才会打印行。

如果您愿意,可以从shell传递值:

$ c=2
$ awk -v c="$c" '/pattern1/{++f;p=1}p&&f==c;/pattern2/{p=0}' file
pattern1
ef
pattern2

打印最后一次出现

要始终打印范围内的最后一个匹配项,可以使用数组:

$ awk '{a[NR]=$0}/pattern1/{s=NR}/pattern2/{e=NR}END{for(i=s;i<=e;++i)print a[i]}' file
pattern1
ef
pattern2

解释

文件中的每一行都按顺序存储在数组a中。每次匹配开始或结束模式时,se都会被当前行号NR覆盖。最后,打印您感兴趣的元素。

这种方法的一个潜在缺点是整个文件的内容都存储在内存中,但除非你有非常大的文件,否则这可能不是问题。

答案 1 :(得分:1)

另一种方式


找到第n次出现

awk -vM=2 '(x+=/pattern1/)==M&&x+=/pattern2/' file

输出

pattern1
ef
pattern2

解释

-vM=2

将M设置为您想要查找的任何内容

(x+=/pattern1/)==M

x每次出现时增加pattern1,并检查它是否等于M

&&x+=/pattern2/

如果确实如此,那么每次出现pattern2时都会增加它,所以当它到达模式2时,它会打印出那条线,但不会更多,因为它现在会大于M。

awk的默认操作是打印。


打印最后一次出现

这只存储在内存中看到的最后一个块。

awk 'x+=/pattern1|pattern2/{!y++&&B="";B=B?B"\n"$0:$0;x==2&&y=x=0}END{print B}' file

输出

pattern1
ef
pattern2

解释

每次出现pattern1或2时增加x 当没有设置y时(当找到新的集合时)刷新B然后设置y
如果x存在则将线添加到变量B
如果计数为2则取消设置x和y意味着两者都已被看到。

答案 2 :(得分:0)

Perl救援!

打印最后一场比赛:

perl -ne 'push @keep, $_ if (/pattern1/ and @keep = ("")) .. /pattern2/;
          }{ print @keep'

说明:匹配存储在@keep中,当pattern1匹配时,该匹配将被清空。因此,@ keep将在处理完整个输入后包含最后一个匹配。

打印第n场比赛:

perl -ne 'push @keep, $_
              if (/pattern1/ and ++$c and @keep = "")
              .. ($e = /pattern2/);
          print(@keep), last if $e and 2 == $c'
#                                      ^
#                                      |
#                                the second match

$ c计算比赛次数。 $ e表示比赛结束。