Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 如何打印两种模式之间的行,包括或排除(在sed、AWK或Perl中)?_Shell_Perl_Awk_Sed_Pattern Matching - Fatal编程技术网

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
    到文件末尾的行
打印PAT1和PAT2之间的行-不包括PAT1和PAT2 这将使用
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
  • -P
    perl regexp,PCRE。并非在所有
    grep
    变体中
  • -z
    将输入视为一组行,每行 以零字节而不是换行符终止
  • -o
    仅打印匹配项
  • (?s)
    DotAll,即dot也可以查找换行符
  • (.*)
    非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