如何在两个相似模式之间选择线

时间:2018-02-12 12:03:12

标签: awk

我有一个包含这样的文本块的文本文件:

IN
hit
ER 123 hit 456
abc
hit
ghi
ER 789 hit 012
abc
ghi
IN 345 
abc
def
ghi
ER 678 xxx 901
xyz
hit
xyz
IN
risk
in

块可以包含任意数量的行,但始终以包含ER或IN的行开头。

使用awk如何选择两个相似标记模式之间出现的行?

1)可能有多个部分标有这些模式。

2)模式之间选定的一条线必须包含另一种模式(例如命中)

3)应包括第一个模式(例如ER)的行,排除第二个行(例如ER | IN)。

预期产出:

ER 123 hit 456
abc
hit
ghi
ER 678 xxx 901
xyz
hit
xyz

我试图用

实现我的目标
awk '/ER/ {block=1} block {str=str sep $0; sep=RS} /ER|IN/ {block=0; if (str~/hit/) {print str} str=sep=""}'

但它给了我

ER abc hit ghi
ER 789 hit 012
编辑:我的例子不够准确。 EDIT2:

a)我试图找到线匹配模式“ER” b)我搜索最近的下一行匹配模式“ER”或“IN” c)我想仅在我的结果包含至少一行匹配模式“。 hit。”时打印结果,但它不能是第一行。结果应包括第一行,但排除最后一行,所以:

ER 678 xxx 901
xyz
hit
xyz
应打印

,因为在匹配“ER”的行与匹配“IN”的行之间的块中有一行匹配

ER 789 hit 012
abc
ghi
不应该打印

,因为在匹配“ER”的行和符合“IN”的行之间的块中没有匹配的行匹配

3 个答案:

答案 0 :(得分:1)

请您试着跟随并告诉我这是否对您有帮助。

awk '
/ER/ && val{
  if(hit_flag){
    print val};
  val=hit_flag=token=in_er_token=""
}
/ER/ && !val{
  val=$0;
  token=1
  next
}
val && token && (/[Hh][Ii][Tt]/){
  hit_flag=1
}
val && token && (/ER/ || /[Ii][Nn]/){
  if(val){
    in_er_token=1
    };
  next}
!in_er_token{
  val=val?val ORS $0:$0
}
END{
  if(val && hit_flag){
    print val}
}
'   Input_file

答案 1 :(得分:1)

Awk 解决方案:

awk '/^(ER|IN)\>/{
         if (f) { if (r ~ /\<hit\>/) print head, r }
         f=1; head=$0; r=""; next
     }
     f{ r=r ORS $0 }' file

输出:

ER 123 hit 456 
abc
hit
ghi
ER 678 hit 901 
xyz
hit
xyz

答案 2 :(得分:1)

将GNU awk与RT

一起使用
$ awk 'BEGIN{RS="(ER|IN)"}NR==1{rt=RT}{ORS=RT}/\nhit/{print (NR==2?rt:"")$0}' file
ER 123 hit 456
abc
hit
ghi
ER 678 xxx 901
xyz
hit
xyz

说明:

$ awk '
BEGIN { RS="(ER|IN)" }      # record separator is ER or IN
NR==1 { rt=RT }             # special handling it hit is in the second record
{ ORS=RT }                  # set matched RS as ORS
/\nhit/ {                   # hit in the record
    print (NR==2?rt:"") $0  # output with special handling for NR==2
}' file

ERIN以及hit的定义可能会更严格。请注意,当您根据实际需要实施它时。