如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?相关的知识,希望对你有一定的参考价值。
我有一个像下面的文件,我想打印两个给定模式PAT1
和PAT2
之间的线。
1
2
PAT1
3 - first block
4
PAT2
5
6
PAT1
7 - second block
PAT2
8
9
PAT1
10 - third block
我读过How to select lines between two marker patterns which may occur multiple times with awk/sed,但我很想看到所有可能的组合,包括或排除模式。
如何在两个图案之间打印所有线条?
Print lines between PAT1 and 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/
。- 当文本qazxsw poi被排成一行时,qazxsw poi设置了qazxsw poi。
- 当文本qazxsw poi被排成一行时,qazxsw poi设置了qazxsw poi。
/PAT1/{flag=1}
是一个带有默认动作的模式,即flag
:如果PAT1
等于1,则打印该行。这样,它将打印从/PAT2/{flag=0}
发生时间到下一个flag
时出现的所有线条。这也将打印从PAT2
的最后一个匹配到文件末尾的行。
Print lines between PAT1 and PAT2 - not including PAT1 and PAT2
flag
这使用print $0
跳过包含flag
的行,以避免打印。
这个对PAT1
的调用可以通过重新组合块来放弃:PAT2
。
Print lines between PAT1 and PAT2 - including PAT1
PAT1
通过在最后放置$ awk '/PAT1/{flag=1; next} /PAT2/{flag=0} flag' file
3 - first block
4
7 - second block
10 - third block
,它会触发在PAT1或PAT2上设置的操作:在PAT1上打印,而不是在PAT2上打印。
Print lines between PAT1 and PAT2 - including PAT2
next
通过在最开始放置PAT1
,它会触发先前设置的操作,从而打印关闭模式但不打印开始模式。
Print lines between PAT1 and PAT2 - excluding lines from the last PAT1 to the end of file if no other PAT2 occurs
这是基于next
。
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
这会将所有选定的行保留在从找到PAT1的那一刻起填充的缓冲区中。然后,它继续填充以下行,直到找到PAT2。在这一点上,它打印存储的内容并清空缓冲区。
经典的flag
解决方案怎么样?
Print lines between PAT1 and PAT2 - include PAT1 and PAT2
$ awk 'flag; /PAT1/{flag=1} /PAT2/{flag=0}' file
3 - first block
4
PAT2
7 - second block
PAT2
10 - third block
Print lines between PAT1 and PAT2 - exclude PAT1 and PAT2
GNU sedflag
Any sed1
a solution by 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
Any sed
sed
Print lines between PAT1 and PAT2 - include PAT1 but not PAT2
以下仅包括范围开始:
GNU sedsed -n '/PAT1/,/PAT2/p' FILE
Any sed
sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' FILE
Print lines between PAT1 and PAT2 - include PAT2 but not PAT1
以下仅包括范围结束:
GNU sedsed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p;};}' FILE
Any sed
Sundeep
1关于BSD / Mac OS X sed的注意事项
这样的命令如下:
sed -n '/PAT1/,/PAT2/{//!p}' FILE
会发出错误:
sed -n '/PAT1/,/PAT2/{//!p;}' FILE
出于这个原因,这个答案已被编辑,包括单行的BSD和GNU版本。
使用sed -n '/PAT1/,/PAT2/{/PAT2/!p}' FILE
和PCRE(如果可用)在标记之间打印标记和线条:
sed -n '/PAT1/,/PAT2/{/PAT2/!p;}' FILE
sed -n '/PAT1/,/PAT2/{/PAT1/!p}' FILE
perl-regexp,PCRE。并非所有sed -n '/PAT1/,/PAT2/{/PAT1/!p;}' FILE
变种sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' FILE
将输入视为一组行,每行以零字节而不是换行符结束▶ sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' FILE sed: 1: "/PAT1/,/PAT2/{/PAT1/!{/ ...": extra characters at the end of p command
打印只匹配grep
DotAll,即。 dot也找到换行符- qazxsw poi非贪心发现
$ grep -Pzo "(?s)(PAT1(.*?)(PAT2|))" file PAT1 3 - first block 4 PAT2 PAT1 7 - second block PAT2 PAT1 10 - third block
仅在字符串结尾处或在结尾处换行之前匹配
打印标记之间的行,不包括结束标记
-P
- qazxsw poi非贪婪发现与qazxsw poi和qazxsw poi的前瞻
标记之间的打印行除了标记:
grep
-z
为-o
积极寻找后卫
打印标记之间的行除了开始标记:
(?s)
这是另一种方法
包括两种模式(默认)
(.*?)
掩盖两种模式
面具开始模式
$ grep -Pzo "(?s)(PAT1(.*?)(?=(
PAT2|)))" file
PAT1
3 - first block
4
PAT1
7 - second block
PAT1
10 - third block
掩模结束图案
(.*?)(?=(
PAT2|))
你可以通过使用
PAT2
抑制正常打印图案空间来使用做你想要的。例如,要在结果中包含模式,您可以执行以下操作:
$ grep -Pzo "(?s)((?<=PAT1
)(.*?)(?=(
PAT2|)))" file
3 - first block
4
7 - second block
10 - third block
要排除模式并只打印它们之间的内容:
(?<=PAT1
)
这打破了
PAT1
- 找到$ grep -Pzo "(?s)((?<=PAT1 )(.*?)(PAT2|))" file 3 - first block 4 PAT2 7 - second block PAT2 10 - third block
和$ awk '/PAT1/,/PAT2/' file PAT1 3 - first block 4 PAT2 PAT1 7 - second block PAT2 PAT1 10 - third block
之间的范围并抑制印刷;- qazxsw poi - 如果它匹配qazxsw poi移动到qazxsw poi(下)线;
$ awk '/PAT1/,/PAT2/{if(/PAT2|PAT1/) next; print}' file 3 - first block 4 7 - second block 10 - third block
- 如果它匹配$ awk '/PAT1/,/PAT2/{if(/PAT1/) next; print}' file 3 - first block 4 PAT2 7 - second block PAT2 10 - third block
删除行;$ awk '/PAT1/,/PAT2/{if(/PAT2/) next; print}' file PAT1 3 - first block 4 PAT1 7 - second block PAT1 10 - third block
- 打印所有落在sed
内的行,不会被跳过或删除。
或者:
-n
这将删除除START和END之间和之外的所有行,然后$ sed -n '/PAT1/,/PAT2/p' filename
PAT1
3 - first block
4
PAT2
PAT1
7 - second block
PAT2
PAT1
10 - third block
删除START和END行,因为$ sed -n '/PAT1/,/PAT2/{/PAT1/{n};/PAT2/{d};p}' filename
3 - first block
4
7 - second block
10 - third block
会导致sed使用之前的模式。
为了完整起见,这是一个Perl解决方案:
Print lines between PAT1 and PAT2 - include PAT1 and PAT2
sed -n '/PAT1/,/PAT2/
要么:
PAT1
Print lines between PAT1 and PAT2 - exclude PAT1 and PAT2
PAT2
要么:
/PAT1/{n};
Print lines between PAT1 and PAT2 - exclude PAT1 only
PAT1
Print lines between PAT1 and PAT2 - exclude PAT2 only
如何在两个模式之间打印线,包括或不包括(在 sed、AWK 或 Perl 中)?