目录
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就结束了