Shell 如何打印两种模式之间的行,包括或排除(在sed、AWK或Perl中)?
我有一个如下文件,我想打印两个给定模式Shell 如何打印两种模式之间的行,包括或排除(在sed、AWK或Perl中)?,shell,perl,awk,sed,pattern-matching,Shell,Perl,Awk,Sed,Pattern Matching,我有一个如下文件,我想打印两个给定模式PAT1和PAT2之间的行 1 2. 第1部分 3-第一座 4. 第二部分 5. 6. 第1部分 7秒街区 第二部分 8. 9 第1部分 10-第三座 我已经读过了,但我很好奇看到所有可能的组合,包括或排除模式 如何打印两个图案之间的所有线条?打印PAT1和PAT2之间的线条 或者,使用变量: awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}' file 这是怎么回事 /PAT1/匹配包含此文本的行,以及/PAT2/匹配
PAT1
和PAT2
之间的行
1
2.
第1部分
3-第一座
4.
第二部分
5.
6.
第1部分
7秒街区
第二部分
8.
9
第1部分
10-第三座
我已经读过了,但我很好奇看到所有可能的组合,包括或排除模式
如何打印两个图案之间的所有线条?打印PAT1和PAT2之间的线条
或者,使用变量:
awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}' file
这是怎么回事
匹配包含此文本的行,以及/PAT1/
匹配包含此文本的行李>/PAT2/
在一行中找到文本/PAT1/{flag=1}
时设置PAT1
标志
在一行中找到文本/PAT2/{flag=0}
时,取消设置PAT2
标志
是具有默认操作的模式,即打印$0:如果标志
等于1,则打印该行。这样,它将打印从标志
出现到下一个PAT1
出现的所有行。这还将打印从上次匹配的PAT2
到文件末尾的行PAT1
next
跳过包含PAT1
的行,以避免打印该行
对next
的调用可以通过重新排列块来放弃:awk'/PAT2/{flag=0}flag/PAT1/{flag=1}'文件
打印PAT1和PAT2之间的行-包括PAT1
通过在最末端放置标志
,它触发在PAT1或PAT2上设置的操作:在PAT1上打印,而不是在PAT2上打印
打印PAT1和PAT2之间的行-包括PAT2
通过在最开始处放置标志
,它将触发先前设置的操作,从而打印结束模式,而不是开始模式
打印PAT1和PAT2之间的行-如果没有其他PAT2出现,则排除从最后一个PAT1到文件末尾的行
这是基于
作为一个班轮:
$ 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。此时,它将打印存储的内容并清空缓冲区。使用带PCRE的
grep
(如果可用)打印标记和标记之间的行:
$ grep -Pzo "(?s)(PAT1(.*?)(PAT2|\Z))" file
PAT1
3 - first block
4
PAT2
PAT1
7 - second block
PAT2
PAT1
10 - third block
$ grep -Pzo "(?s)(PAT1(.*?)(?=(\nPAT2|\Z)))" file
PAT1
3 - first block
4
PAT1
7 - second block
PAT1
10 - third block
$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(?=(\nPAT2|\Z)))" file
3 - first block
4
7 - second block
10 - third block
$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(PAT2|\Z))" file
3 - first block
4
PAT2
7 - second block
PAT2
10 - third block
perl regexp,PCRE。并非在所有-P
变体中grep
将输入视为一组行,每行 以零字节而不是换行符终止-z
仅打印匹配项-o
DotAll,即dot也可以查找换行符(?s)
非reedy查找(.*)
仅在字符串末尾或末尾换行符之前匹配\Z
$ grep -Pzo "(?s)(PAT1(.*?)(PAT2|\Z))" file
PAT1
3 - first block
4
PAT2
PAT1
7 - second block
PAT2
PAT1
10 - third block
$ grep -Pzo "(?s)(PAT1(.*?)(?=(\nPAT2|\Z)))" file
PAT1
3 - first block
4
PAT1
7 - second block
PAT1
10 - third block
$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(?=(\nPAT2|\Z)))" file
3 - first block
4
7 - second block
10 - third block
$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(PAT2|\Z))" file
3 - first block
4
PAT2
7 - second block
PAT2
10 - third block
对(.*?(=(\nPAT2|\Z))
和\nPAT2
\Z
$ grep -Pzo "(?s)(PAT1(.*?)(PAT2|\Z))" file
PAT1
3 - first block
4
PAT2
PAT1
7 - second block
PAT2
PAT1
10 - third block
$ grep -Pzo "(?s)(PAT1(.*?)(?=(\nPAT2|\Z)))" file
PAT1
3 - first block
4
PAT1
7 - second block
PAT1
10 - third block
$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(?=(\nPAT2|\Z)))" file
3 - first block
4
7 - second block
10 - third block
$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(PAT2|\Z))" file
3 - first block
4
PAT2
7 - second block
PAT2
10 - third block
这是另一种方法 包括两种模式(默认) 屏蔽两种模式
$ 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
遮罩末端图案
$ 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
解决方案怎么样
打印PAT1和PAT2之间的行-包括PAT1和PAT2
sed-n'/PAT1/,/PAT2/p'文件
打印PAT1和PAT2之间的行-排除PAT1和PAT2
逗号分隔符
sed-n'/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}文件
任何sed1
sed-n'/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p;};}文件
甚至(谢谢):
逗号分隔符
sed-n'/PAT1/,/PAT2/{/!p}文件
任何sed
sed-n'/PAT1/,/PAT2/{/!p;}文件
打印PAT1和PAT2之间的行-包括PAT1,但不包括PAT2
以下仅包括范围开始:
逗号分隔符
sed-n'/PAT1/,/PAT2/{/PAT2/!p}文件
任何sed
sed-n'/PAT1/,/PAT2/{/PAT2/!p;}文件
打印PAT1和PAT2之间的行-包括PAT2,但不包括PAT1
以下仅包括范围端:
逗号分隔符
任何sed
1关于BSD/Mac OS X sed的注意事项 下面是这样的命令:
sed-n'/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}文件
将发出一个错误:
▶ sed-n'/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}'文件
sed:1:“/PAT1/,/PAT2/{/PAT1/!{/…”:p命令末尾的额外字符
因此,此答案已编辑为包含一行程序的BSD和GNU版本。您可以使用
sed
执行您想要的操作,方法是使用-n
抑制图案空间的正常打印。例如,要在结果中包含图案,您可以执行以下操作:
$ sed -n '/PAT1/,/PAT2/p' filename
PAT1
3 - first block
4
PAT2
PAT1
7 - second block
PAT2
PAT1
10 - third block
要排除模式并仅打印模式之间的内容,请执行以下操作:
$ sed -n '/PAT1/,/PAT2/{/PAT1/{n};/PAT2/{d};p}' filename
3 - first block
4
7 - second block
10 - third block
它分解为
-定位sed-n'/PAT1/,/PAT2/
和PAT1
之间的范围并抑制打印PAT2
-如果匹配/PAT1/{n};
则移动到PAT1
(下一行)n
-如果匹配/PAT2/{d};
删除行PAT2
-打印属于p
且未被跳过或删除的所有行/PAT1/、/PAT2/
sed '/START/,/END/!d;//d'
这将删除除开始和结束之间的行以外的所有行,然后
//d
删除开始和结束行,因为//
会导致sed使用前面的模式。为了完整起见,下面是一个Perl解决方案:
打印PAT1和PAT2之间的行-包括PAT1和PAT2
perl-ne'/PAT1//PAT2/和print'文件
或:
perl-ne'
zsh sedTester.sh 11.89s user 39.63s system 81% cpu 1:02.96 total
zsh awkTester.sh 38.73s user 60.64s system 79% cpu 2:04.83 total
sed -n '/PAT1/{:a:N;/PAT2/!ba;p}' file
# PAT1 to PAT2 without PAT1
sed -n '/PAT1/{:a;N;/PAT2/!ba;s/^[^\n]*\n//p}' file
# PAT1 to PAT2 without PAT2
sed -n '/PAT1/{:a;N;/PAT2/!ba;s/\n[^\n]*$//p}' file
# PAT1 to PAT2 without PAT1 and PAT2
sed -n '/PAT1/{:a;N;/PAT2/!ba;/\n.*\n/!d;s/^[^\n]*\n\|\n[^\n]*$/gp}' file