如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?相关的知识,希望对你有一定的参考价值。

我有一个像下面的文件,我想打印两个给定模式PAT1PAT2之间的线。

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 sed
flag
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 ):

GNU sed
$ 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 sed
sed -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 sed
sed -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 中)?

sed 行编辑器知识汇总

sed 或 awk:删除模式后面的 n 行

使用 sed 或 awk 按照匹配模式打印一行

Linux三剑客(sed)-编辑匹配到的文本

sed 命令操作