如何在 Linux 中使用 sed 提取两个模式之间的字符串,而第二个模式在文件中重复更多行

如何在 Linux 中使用 sed 提取两个模式之间的字符串,而第二个模式在文件中重复更多行

例如

xyz
A1
B1
C1
D1
End
End
End
X1
X2
X3
Done

我想提取 xyz 到结束模式之间的所有字符串。所以输出应该是

xyz
A1
B1
C1
D1
End
End
End

答案1

方法一

perl -l -0777ne 'print /^(xyz.*?^End$(?:\nEnd$)*)/ms' yourfile

在职的

  • 读取文件,使其显示为一个很长的字符串,然后可以使用适当的正则表达式将其拆开。本例中的正则表达式是:
    • 在行(不一定是文件)的开头查找 xyz。
    • 单独查找一行上最近的 End,然后查找尽可能多的连续行。

方法2

perl -lne '
   next unless /xyz/ ... eof;
   last if !/End/ and $flag;
   $flag ||= 1 if /End/;
   print;
' yourfile

在职的

  • 在这里,我们以每行为基础操作 Perl 并设置一个小型状态机。
    • 拒绝文件的任何非范围部分。
    • 一旦我们输入正确的范围,我们就会打印所有行,直到到达 /End/ 行。那时我们设置了标志。
    • 然后,当我们看到第一条非/End/行时,我们就会爆发。

方法3

sed -e '
   /xyz/!d
   :a
      $q;N
   /\nEnd$/!ba
   :b
      n
   /End/bb
   d
' yourfile

在此方法中,我们操作第一个 do-while 循环 (:a),它将累积从 /xyz/ 到 /End/ 的行。

第二个 do-while 循环 (:b) 将打印行,直到下一行恰好是 /End/。

方法4

sed -e '
   /xyz/,/End/!d
   H;/xyz/h;/End/!d
   :a
      $q;N
      /\(.*\)\n\1$/!{g;q;}
      s/.*\n//;H
   ba
' yourfile

使用这种方法,我们首先选择正确的范围,然后将该范围数据存储在保存空间中。 do-while 循环 (:a) 设置为增量追加到保留空间,而下一行恰好是 /End/。

结果

xyz
A1
B1
C1
D1
End
End
End

答案2

这是一种pcregrep擅长的工作:

pcregrep -M 'xyz(.|\n)*End' file

请注意,它非常贪吃,直到最后才吃掉所有东西结尾,包括其他结尾s。

答案3

Perl 来救援:打印第一行xyz和最后一行之间的所有行End

 perl -ne '
     $inside = 1        if /^xyz$/;
     $seen_end = 1      if $inside && /^End$/;
     push @buff, $_     if $inside;
     print splice @buff if /^End$/ && @buff;
' input-file

从第一次出现开始xyz,我们开始将所有行推入缓冲区。一旦End遇到,我们输出并清除缓冲区(参见拼接),但我们继续将行推入缓冲区,以防End稍后出现另一个行。

答案4

awk解决方案:

awk '/xyz/,/End/{ print $0; n=NR }($0=="End" && n && NR>n && NR-n++ == 1)' file

输出:

xyz
A1
B1
C1
D1
End
End
End

  • /xyz/,/End/- 记录范围,从xyzEnd

  • n=NR- 捕获记录编号(在范围匹配上 - 最终将包含该范围的最后一条记录的编号)

相关内容