如何在包含或不包含(在 sed、AWK 或 Perl 中)的两个模式之间打印线? [英] How to print lines between two patterns, inclusive or exclusive (in sed, AWK or Perl)?
问题描述
我有一个如下所示的文件,我想打印两个给定模式 PAT1
和 PAT2
之间的行.
I have a file like the following and I would like to print the lines between two given patterns PAT1
and PAT2
.
1
2
PAT1
3 - first block
4
PAT2
5
6
PAT1
7 - second block
PAT2
8
9
PAT1
10 - third block
我已经阅读了如何在两个标记模式之间选择线,这可能会用 awk/sed 多次出现,但我是很想看到所有可能的组合,包括或不包括模式.
I have read How to select lines between two marker patterns which may occur multiple times with awk/sed but I am curious to see all the possible combinations of this, either including or excluding the pattern.
如何打印两个图案之间的所有线条?
How can I print all lines between two patterns?
推荐答案
打印 PAT1 和 PAT2 之间的行
$ awk '/PAT1/,/PAT2/' file
PAT1
3 - first block
4
PAT2
PAT1
7 - second block
PAT2
PAT1
10 - third block
或者,使用变量:
awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}' file
这是如何工作的?
/PAT1/
匹配具有此文本的行,就像/PAT2/
一样./PAT1/{flag=1}
在一行中找到文本PAT1
时设置flag
./PAT2/{flag=0}
在一行中找到文本PAT2
时取消设置flag
.flag
是一个带有默认动作的模式,即print $0
:如果flag
等于 1,则打印该行.这样,它将打印从PAT1
出现到下一个PAT2
出现的所有行.这还将打印从PAT1
的最后一个匹配到文件末尾的行.
/PAT1/
matches lines having this text, as well as/PAT2/
does./PAT1/{flag=1}
sets theflag
when the textPAT1
is found in a line./PAT2/{flag=0}
unsets theflag
when the textPAT2
is found in a line.flag
is a pattern with the default action, which is toprint $0
: ifflag
is equal 1 the line is printed. This way, it will print all those lines occurring from the timePAT1
occurs and up to the nextPAT2
is seen. This will also print the lines from the last match ofPAT1
up to the end of the file.
$ awk '/PAT1/{flag=1; next} /PAT2/{flag=0} flag' file
3 - first block
4
7 - second block
10 - third block
这使用 next
跳过包含 PAT1
的行以避免打印.
This uses next
to skip the line that contains PAT1
in order to avoid this being printed.
对 next
的调用可以通过重新排列块来删除: awk '/PAT2/{flag=0} flag;/PAT1/{flag=1}' 文件
.
This call to next
can be dropped by reshuffling the blocks: awk '/PAT2/{flag=0} flag; /PAT1/{flag=1}' file
.
$ awk '/PAT1/{flag=1} /PAT2/{flag=0} flag' file
PAT1
3 - first block
4
PAT1
7 - second block
PAT1
10 - third block
通过将 flag
放在最后,它会触发在 PAT1 或 PAT2 上设置的操作:在 PAT1 上打印,而不是在 PAT2 上打印.
By placing flag
at the very end, it triggers the action that was set on either PAT1 or PAT2: to print on PAT1, not to print on PAT2.
$ awk 'flag; /PAT1/{flag=1} /PAT2/{flag=0}' file
3 - first block
4
PAT2
7 - second block
PAT2
10 - third block
通过在最开始放置flag
,它会触发之前设置的动作,因此打印结束模式而不是开始模式.
By placing flag
at the very beginning, it triggers the action that was set previously and hence print the closing pattern but not the starting one.
这是基于 Ed Morton 的解决方案.
awk 'flag{
if (/PAT2/)
{printf "%s", buf; flag=0; buf=""}
else
buf = buf $0 ORS
}
/PAT1/ {flag=1}' file
作为单线:
$ awk 'flag{ if (/PAT2/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /PAT1/{flag=1}' file
3 - first block
4
7 - second block
# note the lack of third block, since no other PAT2 happens after it
这会将所有选定的行保留在从找到 PAT1 的那一刻起填充的缓冲区中.然后,它会不断填充以下行,直到找到 PAT2.在这一点上,它打印存储的内容并清空缓冲区.
This keeps all the selected lines in a buffer that gets populated from the moment PAT1 is found. Then, it keeps being filled with the following lines until PAT2 is found. In that point, it prints the stored content and empties the buffer.
这篇关于如何在包含或不包含(在 sed、AWK 或 Perl 中)的两个模式之间打印线?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!