这篇文章上次修改于 1705 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
Sed
sed简介
- sed是一款流编辑工具,用来对文本进行过滤和替换操作,可以对几十个文件进行统一修改
原理:通过文件管道读取文件内容,默认不会修改源文件,而是将读入的内容复制到缓冲区中,成为模式空间,所有指令操作都在模式空间中进行,然后sed根据相应指令对模式空间中的内容进行处理并输出结果,默认输出至屏幕上
Sed基本语法格式
选 项 | 含 义 |
---|---|
--version | 显示sed版本 |
--help | 显示帮助文档 |
-n,--quiet,--silent | 静默输出 |
-e script | 允许多个指令脚本被执行 |
-f script-file | 从文件中读取脚本指令 |
-i,--in-place | 改选项将直接修改源文件(慎用) |
-l N | 制定l指令可以输出行的长度 |
--posix | 禁用GUN sed扩展功能 |
-r | 在脚本指令中使用扩展正则表达式 |
-s,--separate | 默认情况下,sed把输入的多个文件名作为一个长的连续的输入流。而GUN sed则允许把它们当作单独的文件 |
-u,--unbuffered | 最低限度的缓存输入与输出 |
Sed入门范例
基本格式范例
- a,append表示指令追加
- i,insert表示插入指令
- d,delete表示删除指令
s,substitution表示替换指令
[root@Hyui-VM ~]# cat test DEVICE=eno16777736 BOOTPROTO=static IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=yes [root@Hyui-VM ~]# sed '2a TYPE=Ethernet' test #在第二行之后追加TYPE=Ethernet DEVICE=eno16777736 BOOTPROTO=static TYPE=Ethernet IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=yes [root@Hyui-VM ~]# sed '2i TYPE=Ethernet' test #在第三行之前追加TYPE=Ethernet DEVICE=eno16777736 TYPE=Ethernet BOOTPROTO=static IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=yes [root@Hyui-VM ~]# sed 's/yes/no/g' test #把文本中所有的yes替换成no DEVICE=eno16777736 BOOTPROTO=static IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=no [root@Hyui-VM ~]# sed '3,4d' test #删除三四行的内容 DEVICE=eno16777736 BOOTPROTO=static GATEWAY=192.168.0.254 ONBOOT=yes
如果出现不确定的行号,更多可以使用正则表达式确定操作对象
[root@Hyui-VM ~]# sed '/ONBOOT/a TYPE=Ethernet' test #匹配包含ONBOOT的行,之后添加TYPE=Ethernet DEVICE=eno16777736 BOOTPROTO=static IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=yes TYPE=Ethernet [root@Hyui-VM ~]# sed '/^GATEWAY/d' test #删除以GATEWAY开头的行 DEVICE=eno16777736 BOOTPROTO=static IPADDR=192.168.0.1 NETMASK=25.255.255.0 ONBOOT=yes
可以将sed指令写入脚本文件中,通过sed -f来选取
[root@Hyui-VM ~]# cat sed.sh #This is sed.sh /^$/d [root@Hyui-VM ~]# sed -f sed.sh test #对test文件执行sed.sh指令 DEVICE=eno16777736 BOOTPROTO=static IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=yes
执行多指令使用的方法
[root@Hyui-VM ~]# sed 's/yes/no/;s/static/dhcp/' test #使用分号隔开 DEVICE=eno16777736 BOOTPROTO=dhcp IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=no [root@Hyui-VM ~]# sed -e 's/yes/no/' -e 's/static/dhcp/' test #用-e选项 DEVICE=eno16777736 BOOTPROTO=dhcp IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=no [root@Hyui-VM ~]# sed ' #利用分行 > s/yes/no/ > s/static/dhcp/ > ' test DEVICE=eno16777736 BOOTPROTO=dhcp IPADDR=192.168.0.1 NETMASK=25.255.255.0 GATEWAY=192.168.0.254 ONBOOT=no
操作地址匹配范例
[root@Hyui-VM ~]# sed -n '1~2p' test #打印文件奇数行 DEVICE=eno16777736 IPADDR=192.168.0.1 [root@Hyui-VM ~]# sed '2,8d' test #删除2~8行之间所有行 DEVICE=eno16777736
Sed常用指令
指 令 | 功 能 |
---|---|
s | 替换 |
d | 删除 |
a | 追加 |
i | 插入 |
c | 更改 |
l | 打印(显示非打印字符) |
y | 按字符转换 |
L | 打印(不显示非打印字符) |
p | 打印 |
r | 读入文件内容 |
w | 保存至文件 |
q | 退出 |
指令范例
范例1
[root@Hyui-VM ~]# cat neko.html
<html>
<title>Neko Site</title>
<body>Cute Neko<body>
</html>
如何将neko.html文件中第二个"body"替换成"/body"呢?
#编写一个sed.sh脚本: [root@Hyui-VM ~]# cat sed.sh /body/{ s//\/body/2 }
依据上表可得s代表的是替换指令,不需要替换所有body,只需要替换第二个。
执行这个脚本:
[root@Hyui-VM ~]# sed -f sed.sh neko.html
<html>
<title>Neko Site</title>
<body>Cute Neko</body>
</html>
范例2
[root@Hyui-VM ~]# cat neko.html
<html>
<title>Neko Site</title>
<body>
h1Cute Nekoh1
h2Kawaii Nekoh2
h3Yasashi Nekoh3
</body>
</html>
"h1"、"h2"和"h3"分别表示一级标题、二级标题和三级标题,但是文件中缺少"<>"和"</>",如何使用Sed对文件进行修改纠正呢?
#编写一个sed.sh脚本 [root@Hyui-VM ~]# cat sed.sh /h[0-9]/{ s//\<&\>/1 s//\<\/&\>/2 }
在以上sed脚本中,我们要匹配的是h后跟一个数字的行,将h与数字替换成带有<>和</>的行,也就是将h[0-9]替换为<&>和</&>,&就是前面要替换的内容;其中第一行指令只替换第一个h1,h2和h3;第二行替换第二个h1,h2和h3。
运行脚本:
[root@Hyui-VM ~]# sed -f sed.sh neko.html
<html>
<title>Neko Site</title>
<body>
<h1>Cute Neko</h1>
<h2>Kawaii Neko</h2>
<h3>Yasashi Neko</h3>
</body>
</html>
范例3
[root@Hyui-VM ~]# cat network
DEVICE=eno16777736
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMAST=255.255.255.0
GATEWAY=192.168.0.254
如何删除文件中的空白行?
#编写一个sed.sh脚本 [root@Hyui-VM ~]# cat sed.sh /.*/{ /^$/d }
匹配任意多个字符,如果匹配不到字串的结尾则为空,需要被删除。
运行结果:
[root@Hyui-VM ~]# sed -f sed.sh network
DEVICE=eno16777736
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMAST=255.255.255.0
GATEWAY=192.168.0.254
范例4
[root@Hyui-VM ~]# cat network
DEVICE=eno1245523
ONBOOT=yes
BOOTPROTO=static
NETMAST=255.255.255.0
GATEWAY=192.168.0.254
在BOOTPROTO行下添加一行IPADDR项,内容为192.168.31.125。
[root@Hyui-VM ~]# sed '/BOOTPROTO=static/a IPADDR=192.468.31.125' network DEVICE=eno1245523 ONBOOT=yes BOOTPROTO=static IPADDR=192.468.31.125 NETMAST=255.255.255.0 GATEWAY=192.168.0.254
在NETMAST行的前一行添加IPADDR项,内容为192.168.31.125。
[root@Hyui-VM ~]# sed '/NETMAST/i IPADDR=192.468.31.125' network DEVICE=eno1245523 ONBOOT=yes BOOTPROTO=static IPADDR=192.468.31.125 NETMAST=255.255.255.0 GATEWAY=192.168.0.254
将ONBOOT的值改为no。
[root@Hyui-VM ~]# sed '/ONBOOT/c ONBOOT=no' network DEVICE=eno1245523 ONBOOT=no BOOTPROTO=static NETMAST=255.255.255.0 GATEWAY=192.168.0.254
范例5
[root@Hyui-VM ~]# cat network DEVICE=eno16777736 ONBOOT=yes BOOTPROTO=static IPADDR=192.168.0.1 NETMAST=255.255.255.0 GATEWAY=192.168.0.254
将前两行显示非打印字符。
[root@Hyui-VM ~]# sed -n '1,2l' network DEVICE=eno16777736$ ONBOOT=yes$
显示一二行内容,不显示非显示字符。
[root@Hyui-VM ~]# sed -n '1,2p' network DEVICE=eno16777736 ONBOOT=yes
范例6
[root@Hyui-VM ~]# cat network DEVICE=eno16777736 onboot=yes BOOTPROTO=static ipaddr=192.168.0.1 nEtMaSt=255.255.255.0 GaTeWaY=192.168.0.254
将文件中所有英文字符转为大写。
#编写sed脚本 [root@Hyui-VM ~]# cat sed.sh /.*/{ /.*/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ }
匹配文件中的全部字符,将全部英文字符替换成大写。
运行结果:
[root@Hyui-VM ~]# sed -f sed.sh network
DEVICE=ENO16777736
ONBOOT=YES
BOOTPROTO=STATIC
IPADDR=192.168.0.1
NETMAST=255.255.255.0
GATEWAY=192.168.0.254
范例7
#文件1
[root@Hyui-VM ~]# cat username.txt
HoshinoRinne
HoshinoAoba
HoshinoHibiki
#文件2
[root@Hyui-VM ~]# cat useremail.txt
[email protected]
[email protected]
[email protected]
先读取username.txt内容,后读取useremail.txt内容。
[root@Hyui-VM ~]# cat sed.sh /.*/{ $r useremail.txt }
直接读入useremail.txt文件的内容。
运行结果:
[root@Hyui-VM ~]# sed -f sed.sh username.txt
HoshinoRinne
HoshinoAoba
HoshinoHibiki
[email protected]
[email protected]
[email protected]
Sed高级应用
多行操作Next
Next指令可以通过读取新的输入行,将它追加至模式空间的现有内容之后,来创建多行模式空间。
举例1:
[root@Hyui-VM ~]# cat message.txt Name:Alice, Mail:[email protected] Name:Tim, Mail:[email protected]
使用Next指令编写sed脚本:
[root@Hyui-VM ~]# cat sed.sh #n /Name/{ N L }
- 其中,"#n"意为屏蔽自动输出,不使用的话会重复显示文件原内容和操作结果。"N"为Next指令。"L"为打印(不显示非打印字符)。
运行结果如下:
[root@Hyui-VM ~]# sed -f sed.sh message.txt Name:Alice, Mail:[email protected] Name:Tim, Mail:[email protected]
举例2:
[root@Hyui-VM ~]# cat num.txt 111 222 222 222 333
使用Next编写sed脚本:
[root@Hyui-VM ~]# cat sed.sh #n /222/{ N l }
- 其中先匹配222内容,匹配到以后立即读取下一行内容,使用"l"会打印非打印字符。
运行结果:
[root@Hyui-VM ~]# sed -f sed.sh num.txt 222\n222$ 222\n333$
其中"\n"意为换行符。
多行操作Print
多行打印Print指令为"P",其与小写"p"的区别为:P只输出多行模式空间中的第一部分,直到第一个插入的\n换行符。
举例:
[root@Hyui-VM ~]# cat word.txt aaa bbb ccc ddd eee fff
不使用打印
[root@Hyui-VM ~]# sed '/.*/N' word.txt aaa bbb ccc ddd eee fff
- 这个命令只使用了Next指令读取下一行,新旧内容都是直接使用"\n"分隔,读取下一行后没有任何后续指令,所以会输出源文件所有内容。
使用L打印:
[root@Hyui-VM ~]# sed '/.*/N;L' word.txt aaa bbb aaa bbb ccc ddd ccc ddd eee fff eee fff
- L打印表示显示模式空间的内容,而sed输出后会把源文件内容表示出来。
使用P打印:
[root@Hyui-VM ~]# sed '/.*/N;P' word.txt aaa aaa bbb ccc ccc ddd eee eee fff
- P打印为打印模式空间中第一部分内容直到\n结尾,空间模式内容为aaa\nbbb的话就仅打印aaa。
使用p打印:
[root@Hyui-VM ~]# sed '/.*/N;p' word.txt aaa bbb aaa bbb ccc ddd ccc ddd eee fff eee fff
使用p打印时遇到\n会直接回车换行。
多行操作Delete
[root@Hyui-VM ~]# cat word.txt aaa bbb ccc ddd eee fff
使用Delete指令:
[root@Hyui-VM ~]# sed '/aaa/d' word.txt bbb ccc ddd eee fff
Hold(h,H), Get(g,G)
- Sed拥有一个hole space(保持空间)的缓冲区,模式空间可以复制内容到保持空间,保持空间内容也可以复制到模式空间。
- Hold(h|H) 将模式空间内容复制或追加到保持空间
- Get(g|G) 将保持空间内容复制或追加到模式空间
Exchange(x) 交换保持空间与模式空间的内容
举例:
[root@Hyui-VM ~]# cat word.txt aaa bbb ccc ddd
编写sed脚本:
[root@Hyui-VM ~]# cat sed.sh /aaa/{ h d } /ccc/{ G }
- 脚本中首先匹配aaa字串,将aaa字串复制到保持空间,然后删除aaa字串;随后匹配ccc字串,将保持空间的内容追加到ccc字串的下一行。
运行结果:
[root@Hyui-VM ~]# sed -f sed.sh word.txt bbb ccc aaa ddd
没有评论