如何打印模式1和模式2的第二个匹配之间的行?

如何打印模式1和模式2的第二个匹配之间的行?

测试文件如下:

PATTERN1
a
b
c
PATTERN2
d
e
f
PATTERN2
g
h

我想打印PATTERN1第二个匹配之间的行PATTERN2

PATTERN1
a
b
c
PATTERN2
d
e
f
PATTERN2

答案1

这是一种方法sed

sed '/PATTERN1/,$!d;/PATTERN2/{x;//{x;q;};g;}' infile

这只是删除第一次出现之前的所有行(如果有)PATTERN1,然后在PATTERN2与其匹配的每一行上x更改缓冲区。如果新的模式空间也匹配,则意味着它是第二次出现,因此它x会变回原样q(自动打印后)。如果它不匹配,则意味着它是第一次出现,因此它通过模式空间复制保留空间内容g(因此现在保留缓冲区中有一条匹配的行PATTERN2)并继续...
还有另一种方式awk

awk '/PATTERN1/{t=1}; t==1{print; if (/PATTERN2/){c++}}; c==2{exit}' infile

PATTERN2仅当遇到匹配的行时才开始打印和计数匹配的行数,并在计数器到达PATTERN1时退出。c2

答案2

适合这项工作的工具是pcregrep

pcregrep -M 'PATTERN1(.|\n)*PATTERN2' file

where 选项-M允许模式匹配多行并(.|\n)*匹配任何字符或换行符零次或多次。

请注意,我们利用了 grep 的贪婪性。如果您想将表格pattern1打印到第一的出现pattern2,*?则应使用非贪婪代替*

作为概括,要打印直到n第 次出现的 PATTERN2:

pcregrep -M 'PATTERN1((.|\n)*?PATTERN2){n}' file

更改n为您需要的实际数字。

答案3

只需使用标志:

$ awk '/PATTERN1/{flag=2;next} flag; /PATTERN2/{flag--}' file
a
b
c
PATTERN2
d
e
f
PATTERN2

即:当你发现PATTERN1将标志设置为正值时;特别是 2。然后,当您找到 时PATTERN2,将该标志减一。这样,第二场比赛后就会耗尽。在两者之间,用作在具有真值(2 或 1)时flag触发 的值。{print $0}

答案4

如果我们告诉我们sed很容易收集必要的行然后打印

sed -n '
    /PATTERN1/{
        :1
        $!N
        /\(PATTERN2\).*\1/!b1
        p
    }
' file

相关内容