Awk 如何在匹配之前和之后打印行直到特定匹配(3种匹配模式)

Awk 如何在匹配之前和之后打印行直到特定匹配(3种匹配模式),awk,sed,grep,text-processing,Awk,Sed,Grep,Text Processing,我有一个很长的数据,它是以块为单位构建的 在下面的示例中,让我们看看它们以(AAA)开头,以(FFF)结尾,它们之间可能有许多行信息 我想提取特定的块,仅当模式(CCC)在这些块内时 例如: cat text AAA1 BBB FFF1 AAA2 BBB CCC2 DDD EEE FFF2 AAA3 BBB FFF3 AAA4 BBB CCC4 DDD EEE FFF4 输出应为: AAA2 BBB CCC2 DDD EEE FFF2 AAA4 BBB CCC4 DDD EEE FFF4 我

我有一个很长的数据,它是以块为单位构建的

在下面的示例中,让我们看看它们以(AAA)开头,以(FFF)结尾,它们之间可能有许多行信息

我想提取特定的块,仅当模式(CCC)在这些块内时

例如:

cat text
AAA1
BBB
FFF1
AAA2
BBB
CCC2
DDD
EEE
FFF2
AAA3
BBB
FFF3
AAA4
BBB
CCC4
DDD
EEE
FFF4
输出应为:

AAA2
BBB
CCC2
DDD
EEE
FFF2
AAA4
BBB
CCC4
DDD
EEE
FFF4
我考虑过使用sed,但没有真正起作用: 如果使用此选项,则仅给出从CCC到下一个AAA/FFF的信息:
sed-n-e'/CCC/,/AAA/p'文本
sed-n-e'/CCC/,/AAA/p'文本

CCC2
DDD
EEE
FFF2
AAA3
CCC4
DDD
EEE
FFF4

如果我这样使用:<代码> SED-N-E'/AAA//FFF/P′文本< /代码>,我将捕获AAA和FFF之间没有CCC的模式。

< P>您可以将您的输入视为数据块,以<代码> AAA.*/COD>为开始标记和<代码> FFF.*/COD>作为您的结束标记。现在将每个块收集到保持空间中,并在结束标记处检查块是否包含所需的图案

例如,下面是一个GNU-sed版本,它可以做到这一点:

解析

像这样运行,例如:

sed -nf parse.sed | sed '/^FFF/G'
或作为一个班轮:

sed -n '/^AAA/{h;b};H;/^FFF/{x;/\nCCC/p}' | sed '/^FFF/G'
输出:

AAA2
BBB
CCC2
DDD
EEE
FFF2
AAA4
BBB
CCC4
DDD
EEE
FFF4
更具可移植性的sed脚本如下所示:

# Start-tag -> start a new block in hold-space
/^AAA/ { 
  h
  b
}

# Save input
H

# End-tag AND block contains CCC -> print
/^FFF/ { 
  x
  /\nCCC/p
}
这可能适用于您(GNU-sed):

关闭隐式打印
-n
,因为这是一个筛选操作

匹配包含
AAA
的行,并附加更多行,直到包含
FFF
的行

如果集合包含字符串
CCC
,请打印它

重复一遍

注意:假设
AAA
FFF
成对出现,如果不使用:

sed -n '/AAA/{:a;N;/\n.*AAA/s/.*\n//;/FFF/!ba;/CCC/p}' file
备选方案:

sed -n 'H;/AAA/h;/FFF/{g;/AAA.*CCC/p;z;h}' file
编辑:

对于行首的
AAA
CCC
FFF
,请使用:

sed -n '/^AAA/{:a;N;/^FFF/M!ba;/^CCC/Mp}' file


在每个Unix设备上的任何shell中使用任何awk:

$ awk '/^AAA/{a=1; buf=""} /^CCC/{c=1} {buf=buf $0 ORS} /^FFF/{if (a && c) printf "%s", buf; a=c=0}' text
AAA2
BBB
CCC2
DDD
EEE
FFF2
AAA4
BBB
CCC4
DDD
EEE
FFF4
awk变体

awk '/^AAA/{f=1} f{i=i $0 ORS} /^FFF/{if(i~/\nCCC/){printf "%s", i} i=f=""}' input

欢迎来到SO,请在您的问题中以代码的形式添加您的努力,这是非常值得鼓励的,谢谢。请将
/pat1/,/pat2/
看作一个布尔开关,其中
pat1
将其打开,而
pat2
将其关闭。在CCC之前没有AAA,CCC之前有多个AAA,CCC之后有多个FFS,没有FFF,等等。如果可能的话,你应该在你当前的例子中包括不只是一个晴天案例的样本输入/输出。我理解@EdMorton,但不能把真实数据放得太长。如果您看到该模式,则有以AAA开头、以FFF结尾的段或块,但有些可能有或可能没有CCC。这是我需要匹配的,答案中已经有相当准确的信息。我不建议你把真实数据放在问题中,只是用代表真实数据的值。不存在
AAA的情况。。。AAA。。。CCC。。。例如,在你的问题中,因此,如果你的真实数据中存在这种情况,那么你的不同答案将产生不同的输出,我们不知道哪一个是正确的。这是我在前面提到的例子中提到的一个例子,你的解决方案和我的解决方案将产生相同的输出,但在不同的输入下会产生不同的输出(例如,从输入中删除第一个
FFF1
)因为我假设需要从最接近的AAA打印到CCC,而您的将从最远的.idk打印,这是正确的,或者如果这是不可能的输入。感谢您的建议,这非常有用。我稍微编辑了我的答案。您可能是对的。重新阅读问题后,您的方法(从最接近的AAA打印)更接近OP的目标。谢谢@potong这很简单,但其他一些东西对我不起作用。我将这个额外的正则表达式值^'文件
,sed命令不会执行任何类似于等待其他命令的操作parameters@kgtr<代码> ^ 意味着“字符串的开始”。不能在字符串的中间出现字符串的开始,因此代码> \N**AAA不能匹配任何东西。(除非您的ReXEP引擎在ReGEXP的中间处理一个<代码> ^ <代码>,然后它将匹配某些东西,但不能匹配您想要的!)。您可能是指“代码> \N**NaAA\/CODE”,试图在一行开始时捕获<代码> AAA < /Cord>,但IDK如果您想要的话,也可以这样做。AAA将取代ERE中多行字符串中的
^AAA
,但sed使用BRE,除非它支持
-E
,并且消耗
\n
所以…祝您好运:-)regexp中的@kgtr
^
$
充当行的开始和结束的零宽度锚。如果模式空间中存在多行,则a
\n
可以表示相同的内容,例如,如果模式空间中有两行
\nAAA
将匹配第二行开始处的
AAA
第二种解决方案是这样的,因为
N
在模式空间中附加了以下行。注意
\N.*\nAAA
是错误的,因为这将匹配至少3行或更多行,而不是预期的。我尝试了这一点并成功了!非常感谢,我需要在模式周围放置更多信息,如regex值,并且工作得非常完美!
sed -n '/^AAA/{:a;N;/\nAAA/s/.*\n//;/\nFFF/!ba;/\nCCC/p}' file
sed -n 'H;/^AAA/h;/^FFF/{g;/AAA.*\nCCC/p;z;h}' file
$ awk '/^AAA/{a=1; buf=""} /^CCC/{c=1} {buf=buf $0 ORS} /^FFF/{if (a && c) printf "%s", buf; a=c=0}' text
AAA2
BBB
CCC2
DDD
EEE
FFF2
AAA4
BBB
CCC4
DDD
EEE
FFF4
awk '/^AAA/{f=1} f{i=i $0 ORS} /^FFF/{if(i~/\nCCC/){printf "%s", i} i=f=""}' input