1

在我的 Linux 终端中,我需要找到此类事件的数量,其中pattern 1pattern 2出现在两行中,而这两行恰好n相隔几行,而附加要求pattern 3不能出现在这些n行中的任何一行中。例如,如果我有一个文本文件

...
a
* pat1 **
b
c
** pat2 ****
* pat1 **
b
** pat2 ****
*******pat1**
efda
*pat3****
**pat2********
...

n=2and pattern 1is pat1, pattern 2is pat2, and pattern 3ispat3时,那么只有 1 次出现。

如何在awk, grep(或其姐妹)等实用工具中方便地做到这一点。我知道如何使用 python 或 perl 来做到这一点,但只是想知道这些实用工具是否可以做到这一点。

谢谢你。

这是我在阅读@Barmar 的回答后所尝试的

awk -v n=2 '/pat1/ { first = NR } 
           !/pat3/ 
            /pat2/ && first && NR - first == n { count++ } END {print count}'

但我仍然没有正确理解它。我需要针对四种情况执行此操作:

  • pat1并且pat3是相同的。
  • pat2并且pat3是相同的。
  • 这三种模式都是一样的。
  • 其中没有两个是相同的。
4

2 回答 2

2
awk -v n=2 '/pat1/ { first = NR }
            /pat2/ && first && NR - first == n { count++ }
            END {print count}'

这是具有附加pat3要求的代码:

awk -v n=2 '/pat3/ && first { pat3 = 1; first = 0 }
            /pat1/ && !pat3 { first = NR }
            /pat2/ && first && NR - first == n { count++; first = 0 }
            END {print count}'

我认为这适用于所有相同的模式组合,但我还没有测试过。当模式相同时,这个技巧的产生是因为匹配脚本中一个测试的行不会阻止它通过剩余的测试。因此脚本必须重置状态变量pat3,并first避免将同一行视为 apat1pat3match。

在你的尝试中,这条线

!/pat3/

不做任何事情。首先,它在语法上是不正确的——每个测试后都需要一个语句或块来说明匹配时要做什么。其次,即使您在其后放置一个空块,也只是意味着“如果当前行与 pat3 不匹配,则不要执行任何操作”。它对脚本中其他模式匹配的行为没有任何影响。

我想你需要找一个awk教程来学习awk的基本操作模型。我不会尝试在这里教你,这不是一个辅导网站。

于 2013-07-02T03:53:06.807 回答
1

使用

sed -ne '/pat1/{N;N;/\([^\n]*\n\)\{2\}.*pat2/{/pat3/!p}}' input

一些解释:

if (pat1 matches) {                     #  /pat1/{
     read and append 2 lines            #  N;N;
     if (pat2 matches after 2 '\n's) {  #  /\([^\n]*\n\)\{2\}.*pat2/ {
          if (pat3 does not match) {    #  /pat3/!
             print                      #  p
          }                             
      }                                 #  }
 }                                      #  }
于 2013-07-02T04:28:06.653 回答