Sed编辑器高级部分
前一篇文章 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8tgF6eS6-1593678401710)(https://blog.youkuaiyun.com/Leslie_LN/article/details/106852597)]我们介绍的所有sed编辑器命令都是针对的***一行数据***进行操作的;假如我们要匹配查找“this is leslie”短语,但如果这个短语分布在两行,用普通sed编辑器命令来处理文本就不可能成功;针对这种情况,sed编辑器包含了三个处理多行文本的特殊命令:
- N:将数据下一行加进来创建一个多行组来处理
- D:删除多行中的一行
- P:打印多行中的一行
1.1 多行命令
1.1.1 next命令
1.单行next命令
小写的n命令:告诉sed编辑器移动到数据流中的下一行文本
流程:
(1)、查找匹配行
(2)、移动到下一行
(3)、执行命令行列表命令
- 合并文本行
单行的next命令会将数据流中的下一文本行移动到模式空间;多行的next命令会将下一行添加到模式空间中已有的文本后,将数据流中两行文本合并到同一个模式空间中,文本仍然用换行符分隔,但sed编辑器现在会将两行文本当做一行文本处理;
如:
- 查找含有first的那行文本,读入模式空间
- N命令将下一行文本合并到first那行后面
- 替换命令将换行符替换为空格,文本文件中的两行在编辑器的输出中成了一行
***另外一个典型应用:***替换位于两行文字的文本短语
on Tuesday,the Linux System
Administrator's group meeting will be held.
Thank you for your attendance.
All System Administrators should attend.
这儿替换System Administrator’s,注意第一处是位于两行之间,第二处是位于最后一行;
这只是替换了跨多行的短语替换,如果单行有匹配的短语也需要替换:
***注意:***当N命令执行最后一行时,由于没有下一行可读了,N命令就会将编辑器停止;
这儿演示按照书上解释会出现最后一行不会匹配的,按照书上说说所有这儿应该将位于同行的替换命令移动到N命令之前,这样就不会出现上面最后一行未被正确替换的情况:
但是实际演示,好像并不会[P448]:
1.1.2 多行删除命令
单行删除命令(d):删除模式空间中的当前行;
当N和d命令一起使用时:删除的模式空间中的两行如:
多行删除命令(D):只删除模式空间中的第一行;
比如:删除文本中第一行空白行
这儿如果不和N命令使用,很难删除指定的空白行:
sed '/^$/d' data4
删除的文本中所有空白行;
1.1.3 多行打印命令(P)
只打印多行模式空间中的第一行;
1.2 保持空间与模式空间
sed编辑器对应着两块缓冲区(保存文本),即模式空间与保持空间;
模式空间:保存带检查的文本
保存空间:保存临时文本,默认是空白行;
sed编辑器提供了五条操作模式、保持空间的命令:
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
执行:sed -n ‘/first/ {h;p;n;p;g;p}’ data4
执行步骤:
- 首先匹配含有first的行读入模式空间
- h:将模式空间内容复制到保持空间
- p:打印模式空间内容即第一行
- n:移动到第二行,读入模式空间
- p:打印模式空间内容即第二行
- g:复制保持空间内容即第一行到模式空间,此时会先清空模式空间之前的内容
- p:答应模式空间内容即第一行内容
1.3 排除命令(!)
放在命令前,相当于对地址取反,对特定行执行命令;
如:
sed '/header/!p' data4
相当于除了含有header那行不打印外,其他行都打印;
1.4 改变流
1.4.1 分支(b)
格式:
[地址]b [标签]
地址:决定哪些行会触发分支命令
标签:决定可要跳转到的位置,省略这跳转到脚本末尾;以冒号开始:即(:标签名)要指定标签,将它添加到b命令后即可;
2、3行会触发分支命令,由于没有指定分支,即跳转到脚本末尾不会执行后面的连个替换命令;
如果指定标签:
用伪代码解释:
if(2,3){
执行标签后命令
}else{
执行整个命令脚本,包括标签后的命令
}
1.4.2 测试(t)
格式:
根据替换命令结果跳转到某个标签;如果没有指定标签,
伪代码解释:
if(替换命令匹配成功){
跳转到指定标签
}else{
}
格式:
[地址]t [标签]
1.5 模式替代
假如我们替换.at结尾的一个三个字母的单词,在匹配模式中我们可以用 .通配符来表示一个字符,但是在替代模式中无法正确匹配这个通配符,比如:可能是cat、hat…
echo "the cat sleeps in his hat" |sed 's/.at/.at/'
输出结果: the .at sleeps in his .at
比如这里替模式的.并不是代表任意字符的特殊在字符,表示的仅仅就是“.”这个字符
sed编辑器提供了“&”符号 在替代模式中表示匹配的对应文本;如:我们我为对应文本加上双引号:
echo "the cat sleeps in his hat"| sed 's/.at/"&"/
输出结果:the "cat" sleeps in his hat
&提取的是对应的整个匹配文本,如果你只想替换其中一部分文本,这时就需要借助于子模式:
在匹配中()包裹要提取的一部分文本,在替换模式中 /1、/2…来提取对应文本,这里的数值1:对应第一个子模式,2对应第二个子模式,以此类推…
注意:这儿必须使用转义字符将他们标示为分组字符,而不是普通的圆括号,这跟转义其他特殊字符正相反;
echo "this is is leslie,hello world" | sed 's/\(this\) is/\1/'
输出:this is leslie,hello world
实例:对一个比较大的数字插入,
echo "1112345678" | sed '{
:start
s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/p
t start}'
输出:
1112345,678
1112,345,678
1,112,345,678
1,112,345,678
1.6 在脚本中使用sed
当编辑器脚本很长时,如果 每次使用时都键入整个脚本,可想而知得多繁琐。可以将编辑器命令放到***shell包装脚本***中,包装脚本充当着编辑器脚本和命令行之间的中间角色;
在Shell脚本中可以将普通的shell变量即参数和sed编辑器脚本一起使用,比如:将命令行参数作为sed 编辑器脚本输入:
#!/bin/bash
sed -n '1!G;h;$p' S1
运行Shell脚本:
./test data4
1.6.1 重定向sed输出
默认情况,sed编辑器会将脚本的结果输出到STDOUT,在shell脚本中可以使用"$()"将sed编辑器命令输出重定向到一个变量中;
比如:
#!/bin/bash
result=$(echo "1112345678" | sed '{
:start
s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/p
t start}')
1.7 sed使用工具
1.7.1 为文本行增加行间距
G命令:是追加保持空间内容到模式空间后面,前面我们说了,默认情况下,保持空间的为空白的即空白行;
sed '$!G' data4
我将看到相邻两行间将多出一个空白行;
1.7.2 给文本中的行编号
前面我说了借助于“=”来显示行号
可以看见输出行号与文本是两行显示的,借助前面学习的N命令就可实现在每行文本行前显示行号: