sed 提取遵循起始组模式的行

sed 提取遵循起始组模式的行

我目前遇到了一个需要帮助解决的问题。即使指向正确的方向也会有所帮助。

我有一个包含很多行的文件,并且只想提取特定的“组”行(如果它们遵循某种模式)。 (行必须以 开头A,下一行必须以 开头B,下一行必须以 开头C

例如: 模式:按照A, B,C的顺序开始。

输入:

A1
B1
C1
D1
A2
B2
D2
A3
D3
A4
B4
C4
A5
B5
D5

输出:

A1
B1
C1
A4
B4
C4

答案1

另一个解决方案awk

awk 'p2~/^A/ && p1~/^B/ && /^C/{print p2 RS p1 RS $0} {p2=p1; p1=$0}'

perl整个输入作为单个字符串进行读取:

perl -0777 -ne 'print /^A.*\nB.*\nC.*\n/mg'

ripgrep它支持方便的多行匹配选项-U

rg -oUN '^A.*\nB.*\nC.*'

在这里,-o选项仅获取匹配部分,-N选项是防止输出中的行号

答案2

如果您还想要 Sed 解决方案,这很丑陋,但应该可行。

sed -n '
  /^A/{
    N
    /\nB/!D
    N
    /\nC/!{
      s/\n//
      D
    }
    p
  }
' file

-n告诉 sed 不要打印任何内容,除非它到达p命令。

如果你理解了第一块,你就可以理解其余的:

  • /^A/如果模式空间以 A 开头,
    • N将下一行追加到模式空间。
    • /\nB/!D如果模式空间没有后跟 B 的换行符,则删除第一个换行符之前的所有内容,并使用生成的模式空间重新开始,而不读取任何输入。

一班轮:sed -n '/^A/{N;/\nB/!D;N;/\nC/!{s/\n//;D};p}' file

答案3

以下awk程序应该有效:

awk 's==2{if (/^C/) {s=0; p=p ORS $0; print p} else {s=0}}\
     s==1{if (/^B/) {s=2; p=p ORS $0} else {s=0}}\
     s==0{if (/^A/) {s=1; p=$0}}' input.txt 

这将保留一个内部“状态”标志,s以查看我们处于序列中的哪个点(0:未找到开始,1:A找到,2:AB顺序找到),并将文本累积到缓冲区中p

  • 如果找到AB,并且当前行以 开头C,我们将当前行添加到缓冲区并打印它。状态重置为0
  • 如果A找到,并且当前行以 开头B,我们将当前行添加到缓冲区并将状态设置为2(=AB找到)
  • 如果尚未找到开头,并且当前行以 开头A,我们将其添加到缓冲区并将状态设置为1

答案4

您可以在 sed 中设置一个状态机,仅当前一个状态引导您 A->B->C 时才前进到下一个状态

否则,砍头并重新开始。

$ sed -e '$d;/\n/d
    /^A/N;/\nB/!D
    $!N;/\nC/!D
' file
A1
B1
C1
A4
B4
C4

如果你有使用PCRE选项编译的gnu grep,那么下面的grep代码是另一种方式。

$ grep -zoP '(?m)^A.*\nB.*\nC.*\n' file | tr -d '\0'

相关内容