目录

  1.sed跨行匹配&替换

1.1 sed跨行匹配

 1.2 跨行匹配+替换

1.2.1 替换匹配多行中的某一行中数据

1.2.2 替换满足匹配的多行为其他字符

2. grep匹配多行

 3.pcregrep匹配多行


  1.sed跨行匹配&替换

1.1 sed跨行匹配

sed可以跨行匹配并替换,但是只能匹配开始行和一个结束行,无法包括匹配中间行

如下一段文本:匹配包含000,222,111的三行

vwef000
verbweg
111
222
verbweg
fgewrbva
gfqf111
sed -n -e '/000/,/111/p' test.log
>>ivwef000
>>verbweg
>>111

可以看出无法包含222,到第一个111的行就停止了 .如果把/222/也放进去就是错误使用sed

sed -n -e '/000/,/222/,/111/p' test.log
>>sed: -e expression #1, char 12: unknown command: `,'

 1.2 跨行匹配+替换

1.2.1 替换匹配多行中的某一行中数据

还是以上节的文本为例,由于无法同时匹配三行及以上,就替换000,111行中间的verb为XXX

sed -i '/000/,/111/s/verbw/XXX/g' test.log
cat test.log
>>vwef000
>>XXXeg
>>111
>>222
>>verbweb
>>fgewrbva
>>gfqf11b

可以看出只将000,111之间的verb替换为了XXX,另外一个verb没有被替换

1.2.2 替换满足匹配的多行为其他字符

还是以上节的文本为例,就替换以000为开头,111为结尾多行中间的所有字符为XXX

cat test.log
>> vwef000
>> verbweg
>> 111
>> 222
>> verbweg
>> fgewrbva
>> gfqf111

sed -i "{:begin;  /111/! { $! { N; b begin }; }; s/000.*111/XXX/; };" test.log
cat test.log
>> vwefXXX
>> 222
>> verbweg
>> fgewrbva
>> gfqf111

命令解释如下

:begin,这是一个标号,man中叫做label,也就是跳转标记,供b和t命令用,本例中使用了b命令。

/111/!是要替换内容的结束标记,带上!就是说当一行处理完毕之后,如果没有发现结束标记就继续,'111'就是你要结束的搜索词

$!,$在正则中表示字符串结尾,在sed中代表文件的最后一行,本句和上一句结合起来的意思就是:如果在本行没有发现结束标记,并且当前扫描过的行并不是文件的最后一行。

N;,把下一行的内容追加(append)到缓冲区(pattern)之后,在我们的例子中,在处理vwef000这一行的内容时,就会执行到这里,然后把下一行的内容ddd,依次类推把
verbweg一起放入缓冲区,相当于“合并”成了一行(sed的缓冲区中默认都只会包含一行的内容)。

b begin,由于仍然没有找到结束标记'111'(注意上一条说的缓冲区还没有被处理),所以在这里跳回到标号begin,重新开始命令。如果开始和结束标记之间间隔了多行,那么就会有多次跳转发生。

s/000.*111/XXX/;,终于,/111/!不再匹配成功,也就是我们已经找到了结束标记,那么用s命令来进行替换。如果开始和结束标记在一行的话,就会越过上面那些复杂的处理,直接执行到这里了。
 

2. grep匹配多行

要求匹配包含000,222,111的三行

cat test.log
>> vwef000
>> verbweg
>> 111
>> 222
>> verbweg
>> fgewrbva
>> gfqf111
>> vwef000
>> verbweg
>> 111
>> sds

 运行如下命令:

grep -Pz "000(\n|.)*222(\n|.)*111" test.log

其中(\n|.)*表示匹配\n(换行)或.(任意字符)任意次数。

结果如下:红色部分为匹配内容,但是整个文件内容都会显示出来,而且是匹配到最后一个满足条件的111。

选项说明

-P :  --perl-regexp,使用Perl正则表达式;

-z,处理多行;

-l:只输出满足条件的文件名。

grep -Plz "000(\n|.)*222(\n|.)*111" test.log
>> test.log

-o,只输出匹配部分。因为如果进行多行匹配,就没有换行作为匹配结束边界,会返回剩下的全部文本

grep -Pzo "000(\n|.)*222(\n|.)*111" test.log

 

如果加上非贪婪匹配可以只匹配到第一个满足条件的段落,如下:

grep -Pzo "000(\n|.)*222(\n|.)*?111" test.log
>> 000
>> verbweg
>> 111
>> 222
>> verbweg
>> fgewrbva
>> gfqf111

上图可以看到结束行匹配到第一个000,222,111就结束了

 3.pcregrep匹配多行

要求匹配包含000,222,111的三行

首先需要确认Linux中有pcregrep,现在大部分系统中都有。

和上一节同样的文本

cat test.log
>> vwef000
>> verbweg
>> 111
>> 222
>> verbweg
>> fgewrbva
>> gfqf111
>> vwef000
>> verbweg
>> 111
>> sds
pcregrep -Mo "000(\n|.)*222(\n|.)*111" test.log
>> 000
>> verbweg
>> 111
>> 222
>> verbweg
>> fgewrbva
>> gfqf111
>> vwef000
>> verbweg
>> 111

从以上结果看出和grep -Pzo的结果一样。

-M:表示multi-line多行处理

-o:含义和grep一致

如果加上非贪婪匹配可以只匹配到第一个满足条件的段落,如下:

pcregrep -Mo "000(\n|.)*222(\n|.)*?111" test.log
>> 000
>> verbweg
>> 111
>> 222
>> verbweg
>> fgewrbva
>> gfqf111

上图可以看到结束行匹配到第一个000,222,111就结束了

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐