使用 sed 或 awk 在两个正则表达式之间选择文件的块打印部分
Choose block print section of file between two regular expressions using sed or awk
sed -n '/pattern1/,/pattern2/p'
pattern1
a
b
pattern2
cd
pattern1
ef
pattern2
gh
pattern1
ef
pattern2
这将在所有匹配的 pattern1 和 pattern2 之间生成输出
但是我如何选择打印哪个块,比如只打印最后一个匹配的模式块或只打印第一个匹配的模式块?
打印第 N 次出现
这是您可以使用 awk 实现的一种方法:
$ awk '/pattern1/{++f;p=1}p&&f==2;/pattern2/{p=0}' file
pattern1
ef
pattern2
中间的数字 2
控制打印哪一个事件(在本例中为第二个)。
说明
当开始模式匹配时,f
递增并设置 p
标志。当结束模式匹配时,p
标志被取消设置。仅当设置 p
标志且 f
具有特定值时才会打印行。
如果您愿意,可以从 shell:
传递值
$ c=2
$ awk -v c="$c" '/pattern1/{++f;p=1}p&&f==c;/pattern2/{p=0}' file
pattern1
ef
pattern2
打印最后一次出现
要始终打印范围内的最后一次出现,您可以使用数组:
$ awk '{a[NR]=[=12=]}/pattern1/{s=NR}/pattern2/{e=NR}END{for(i=s;i<=e;++i)print a[i]}' file
pattern1
ef
pattern2
说明
文件中的每一行都按顺序存储在数组a
中。每次匹配开始或结束模式时,s
和 e
都会被当前行号 NR 覆盖。最后,打印您感兴趣的元素。
这种方法的一个潜在缺点是整个文件的内容都存储在内存中,但除非您有非常大的文件,否则这可能不是问题。
Perl 来拯救!
正在打印最后一场比赛:
perl -ne 'push @keep, $_ if (/pattern1/ and @keep = ("")) .. /pattern2/;
}{ print @keep'
说明:匹配保存在@keep中,匹配到pattern1
时清空。因此,@keep 将在处理完整个输入后包含最后一个匹配项。
正在打印第 n 个匹配项:
perl -ne 'push @keep, $_
if (/pattern1/ and ++$c and @keep = "")
.. ($e = /pattern2/);
print(@keep), last if $e and 2 == $c'
# ^
# |
# the second match
$c 计算匹配项。 $e 表示比赛结束。
另一种 awk 方式
找到第 n 次出现
awk -vM=2 '(x+=/pattern1/)==M&&x+=/pattern2/' file
输出
pattern1
ef
pattern2
说明
-vM=2
将 M 设置为您要查找的任何事件
(x+=/pattern1/)==M
每次出现 pattern1
时递增 x
并检查它是否等于 M
.
&&x+=/pattern2/
如果确实如此,则每次出现 pattern2
时都会递增它,因此当它到达模式 2 时,它将打印该行,但不再打印,因为它现在将大于 M.
awk 的默认操作是打印。
打印最后一次出现
这只存储内存中看到的最后一个块。
awk 'x+=/pattern1|pattern2/{!y++&&B="";B=B?B"\n"[=15=]:[=15=];x==2&&y=x=0}END{print B}' file
输出
pattern1
ef
pattern2
说明
每次出现 pattern1 或 2 时增加 x
未设置 y 时刷新 B(当找到新集合时)然后设置 y
如果 x 存在,则将行添加到变量 B
如果计数为 2,则取消设置 x 和 y,这意味着两者都已被看到。
sed -n '/pattern1/,/pattern2/p'
pattern1
a
b
pattern2
cd
pattern1
ef
pattern2
gh
pattern1
ef
pattern2
这将在所有匹配的 pattern1 和 pattern2 之间生成输出
但是我如何选择打印哪个块,比如只打印最后一个匹配的模式块或只打印第一个匹配的模式块?
打印第 N 次出现
这是您可以使用 awk 实现的一种方法:
$ awk '/pattern1/{++f;p=1}p&&f==2;/pattern2/{p=0}' file
pattern1
ef
pattern2
中间的数字 2
控制打印哪一个事件(在本例中为第二个)。
说明
当开始模式匹配时,f
递增并设置 p
标志。当结束模式匹配时,p
标志被取消设置。仅当设置 p
标志且 f
具有特定值时才会打印行。
如果您愿意,可以从 shell:
传递值$ c=2
$ awk -v c="$c" '/pattern1/{++f;p=1}p&&f==c;/pattern2/{p=0}' file
pattern1
ef
pattern2
打印最后一次出现
要始终打印范围内的最后一次出现,您可以使用数组:
$ awk '{a[NR]=[=12=]}/pattern1/{s=NR}/pattern2/{e=NR}END{for(i=s;i<=e;++i)print a[i]}' file
pattern1
ef
pattern2
说明
文件中的每一行都按顺序存储在数组a
中。每次匹配开始或结束模式时,s
和 e
都会被当前行号 NR 覆盖。最后,打印您感兴趣的元素。
这种方法的一个潜在缺点是整个文件的内容都存储在内存中,但除非您有非常大的文件,否则这可能不是问题。
Perl 来拯救!
正在打印最后一场比赛:
perl -ne 'push @keep, $_ if (/pattern1/ and @keep = ("")) .. /pattern2/;
}{ print @keep'
说明:匹配保存在@keep中,匹配到pattern1
时清空。因此,@keep 将在处理完整个输入后包含最后一个匹配项。
正在打印第 n 个匹配项:
perl -ne 'push @keep, $_
if (/pattern1/ and ++$c and @keep = "")
.. ($e = /pattern2/);
print(@keep), last if $e and 2 == $c'
# ^
# |
# the second match
$c 计算匹配项。 $e 表示比赛结束。
另一种 awk 方式
找到第 n 次出现
awk -vM=2 '(x+=/pattern1/)==M&&x+=/pattern2/' file
输出
pattern1
ef
pattern2
说明
-vM=2
将 M 设置为您要查找的任何事件
(x+=/pattern1/)==M
每次出现 pattern1
时递增 x
并检查它是否等于 M
.
&&x+=/pattern2/
如果确实如此,则每次出现 pattern2
时都会递增它,因此当它到达模式 2 时,它将打印该行,但不再打印,因为它现在将大于 M.
awk 的默认操作是打印。
打印最后一次出现
这只存储内存中看到的最后一个块。
awk 'x+=/pattern1|pattern2/{!y++&&B="";B=B?B"\n"[=15=]:[=15=];x==2&&y=x=0}END{print B}' file
输出
pattern1
ef
pattern2
说明
每次出现 pattern1 或 2 时增加 x
未设置 y 时刷新 B(当找到新集合时)然后设置 y
如果 x 存在,则将行添加到变量 B
如果计数为 2,则取消设置 x 和 y,这意味着两者都已被看到。