![为什么两个标签之间的 grep 不适用于选项 -z?怎么修?](https://linux22.com/image/198767/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%A4%E4%B8%AA%E6%A0%87%E7%AD%BE%E4%B9%8B%E9%97%B4%E7%9A%84%20grep%20%E4%B8%8D%E9%80%82%E7%94%A8%E4%BA%8E%E9%80%89%E9%A1%B9%20-z%EF%BC%9F%E6%80%8E%E4%B9%88%E4%BF%AE%EF%BC%9F.png)
这个案例:
$ cat t01.txt
xxxyyyzzz
$ cat t01.txt | grep -Po '(?<=xxx).*(?=zzz)'
结果是:
yyy
这是预期的。
然而,这个案例:
$ cat t02.txt
xxx
yyy
zzz
$ cat t02.txt | grep -Pzo '(?<=xxx).*(?=zzz)'
结果是:
<nothing>
这是出乎意料的。
为什么以及如何解决?
答案1
因为默认情况下,.
与 Perl 正则表达式中的换行符不匹配。您需要显式匹配它,或者使用s
正则表达式的标志:
$ < t02.txt grep -Pzo '(?<=xxx\n).*\n(?=zzz)'
yyy
$ < t02.txt grep -Pzo '(?s)(?<=xxx).*(?=zzz)'
yyy
参见例如perlre
手册页:
在“元字符”部分:
. Match any single character except newline Not in [] (under /s, includes newline)
并在“修饰符”中:
s
将字符串视为单行。也就是说,更改"."
为匹配任何字符,甚至是换行符,通常它不会匹配。
答案2
这实际上是预期的行为。.
包括除换行符之外的任何字符。您正在寻找的正则表达式是:
(?<=xxx)\n*.*\n*(?=zzz)
这是一个测试正则表达式的好网站,它也对它的每个部分都有解释,所以你总是知道它为什么会这样:https://regex101.com