使用 AWK/SED/GREP 打印两个模式(可能不是对)之间的所有线条



我知道这个问题有多个实例,例如打印两种模式之间的所有行,独占,仅限第一个实例(在sed,AWK或Perl中) 但我的问题是这两种模式是否可能不配对 - 例如

给定输入

PATTERN1
bbb
ccc
ddd
eee
fff
PATTERN1
ggg
hhh
iii
PATTERN2
jjj
PATTERN2
kkk

我希望最短的范围作为输出:

ggg
hhh
iii

这可能吗?

您能否尝试仅在 GNUawk中根据您显示的示例编写和测试以下内容。

awk '
/PATTERN1/ && found1 && !found2{
found1=found2=val=""
}
/PATTERN1/{
found1=1
next
}
/PATTERN2/{
found2=1
if(found1){
print val
}
found1=found2=val=""
next
}
{
val=(val?val ORS:"")$0
}
' Input_file

给定样本的输出将为:

ggg
hhh
iii

说明:为上述添加详细说明。

awk '                              ##Starting awk program from here.
/PATTERN1/ && found1 && !found2{   ##Checking if PATTERN1 in current line and found1 is SET and found2 is NOT SET then do following.
found1=found2=val=""             ##Nullifying found1, found2 and val variables here.
}
/PATTERN1/{                        ##Checking condition if PATTERN1 is found then do following.
found1=1                         ##Setting found1 here for flagging.
next                             ##next will skip all further statements from here.
}
/PATTERN2/{                        ##Checking condition if PATTERN2 is found then do following.
found2=1                         ##Setting found2 here for flagging.
if(found1){                      ##Checking condition if found1 is SET then do following.
print val                      ##Printing val here.
}
found1=found2=val=""             ##Nullifying found1, found2 and val here.
next                             ##next will skip all further statements from here.
}
{
val=(val?val ORS:"")$0           ##Creating val which has current line value and keep appending it with new line.
}
' Input_file                       ##Mentioning Input_file name here.

awk中,您可以通过保存PATTERN..并在每次遇到PATTERN..时进行比较来做到这一点。在两者之间,您将元素保存在数组中,当您有两个不匹配的模式时,您将输出数组的内容。否则,您将清空数组并重置计数器,例如

awk '! /PATTERN/ {
a[++n]=$0
}
/PATTERN/ {
if ($0 != lastptrn)
for (i=1; i<=n; i++)
print a[i]
delete a
n=0
lastptrn=$0
}
' file

输出

ggg
hhh
iii

如果Perl恰好是您的选择,请您尝试:

perl -0777 -ne '/.*PATTERN1n(.*?)PATTERN2/s && print $1' input

结果:

ggg
hhh
iii
  • -0777选项告诉Perl一次啜饮所有行。
  • 正则表达式s选项告诉Perl在元字符.中包含换行符。
  • .*PATTERN1n缠绕该位置直到上PATTERN1结束。
  • (.*?)指定最短的匹配项,并将$1分配给匹配的行。

另一个:

$ awk '
/PATTERN1/ {                # at starting pattern
f=1                     # flag up
b=""                    # reset buffer
next                    # to exclude the start pattern
}
/PATTERN2/ {                # at ending pattern
print b                 # output buffer
exit                    # no need to continue to the end
}
f {                         # when flag up
b=b (b==""?"":ORS) $0   # buffer records
}' file

要包括开始和结束标记,请删除next并将f {...}移到/PATTERN2/ {...}之前

这可能对你有用(GNU sed):

sed -n '/PATTERN2/{g;/PATTERN1/{s/[^n]*n//p;q}};H;/PATTERN1/h' file

概述:将PATTERN1行复制到保留空间中,但不包括PATTERN2行,然后打印保留空间减去第一行。

处理:将所有行附加到保留空间,当保留空间匹配时,将保留空间替换为PATTERN1的内容。

PATTERN2匹配时,用保留空间覆盖模式空间,如果模式空间包含PATTERN1,则删除第一行,打印模式空间的内容并退出。

最新更新