仅当第一个模式第二次出现时在两个模式之间打印

仅当第一个模式第二次出现时在两个模式之间打印

我想打印两个模式之间的输出,第一个模式应该是文件中的第二次匹配。

例子 -

test.txt

start one
text_1   
end
start two
text_2
end 
start three
text_3
end

这里第一个模式是start,第二个模式是end。模式start应该是文件中的第二次模式匹配。那么输出应该是

start two
text_2
end

答案1

使用awk,可以轻松扩展到任意第 n记录:

awk '/start/ && ++n == 2, /end/' < file

将打印从第二次出现start到第一次出现的行end

打印第二个start记录end(如果有start, start,end序列将会有所不同):

awk '
  /start/, /end/ {
    if (!seen) {seen = 1; n++}
    if (n == 2) print
    if (/end/) seen = 0
  }' < file

或者:

awk '
  !inside && /start/ {inside = 1; n++}
  !inside {next}
  n == 2
  /end/ {inside = 0}' < file 

答案2

sed

sed -n '/start/,/end/n;/start/,/end/{p;/end/q}' file

解释:

  • -n抑制输出
  • 首先/start/,/end/n提取第一个开始到结束块,但不执行任何操作(通过n
  • 然后进行第二个从开始到结束的块/start/,/end/打印,并在到达结束后立即退出p;/end/q

答案3

在这种特殊情况下 - 当输入仅由/start/,/end/块组成时,您可以简单地执行以下操作

sed '1,/end/d;//q' infile

如果这些块之间还有其他行(不匹配end)那么

sed '1,/end/d;/start/,/end/!d;/end/q' infile

对于更一般的情况,当要提取的块是n您可以运行的块时:

n=5
awk  -vc=$n '/start/{i++};{if (i==c){print;if (/end/){exit}}}' infile

答案4

sed -ne '
   /^start/,/^end/!d; # skip non-interesting block
   /^start/H;         # increment hold counter
   G;/\n.*\n.*\n/!d;  # check if 2nd block reached?
   P;/^end/q;         # we"re in 2nd block so print & quit on /end/
' yourfile

perl -l -0777ne 'print+(/^start.*?\nend[^\n]*$/msg)[1]' yourfile

相关内容