一.Sed简介 Sed是一款流编辑工具,用来对文本进行过滤与替换操作,特别是当你想要对几十个配置文件做统一修改时,你会感受到Sed的魅力!Sed通过一次仅读取一行内容来对某些指令进行处理后输出,所以Sed更适合于处理大数据文件。首先,Sed通过文件或管道读取文件内容,但Sed默认并不直接修改源文件,而是将读入的内容复制到缓冲区中,我们称之为模式空间(pattern space),所有的指令操作都是在模式空间中进行的,然后Sed根据相应的指令对模式空间中的内容进行处理并输出结果,默认输出至标准输出(即屏幕上)。Sed的工作流程如下图所示:
二.Sed的基本语法格式Sed从文件中读取数据,如果没有输入文件,则默认对标准输入进程数据进行处理,脚本指令是第一个非“-”开头的参数,具体语法格式如下:
sed [选项]…{脚本指令} [输入文件]选项
含义
–version
显示sed版本
–help
显示帮助文档
-n,–quit,–silent
静默输出,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印模式空间中的内容,该选项可以屏蔽自动打印。
-e script
允许多个脚本指令被执行
-f script-file
从文件中读取脚本指令,对编写自动脚本程序很实用。
-i,–in-place
慎用,该选项将直接修改源文件
-l,N
该选项指令l指令可以输出的行长度,l指令为输出非打印字符。
–posix
禁用GNU sed扩展功能
-r
在脚本指令中使用扩展正则表达式
-s,–separate
默认情况下,sed将把输入的多个文件名作为一个长的连续的输入流,而GNU sed则允许把它们当作单独的文件
-u,–unbuffered
最低限度的缓存输入和输出
三.Sed入门规范1.基本格式规范
Sed通过特定的脚本指令对文件进行处理,这里就简单介绍几个脚本指令操作作为Sed程序的规范。a,append表示追加指令;i,insert表示插入指令;d,delete表示删除指令;s,substitution表示替换指令。Sed脚本指令的基本格式是:[地址]命令(有些命令仅可以对一行操作,有些可以对多行操作),命令也可以用花括号进行组合,是命令序列可以作用于同一个地址:
address{command1command2command3}注意:第一个命令可以和左花括号在同一行,但右花括号必须单独处于一行。此外,命令后添加空格会产生错误。下面的test.txt为操作样本源文件(注意有若干空白行),介绍Sed的用法:
[root@andrew Andrew]# cat -n test.txt 1 DEVICE=eno16777736 2 BOOTPROTO=static 3 IPADDR=192.168.0.1 4 NETMASK=255.255.255.0 5 6 GATEWAY=192.168.0.254 7 8 ONBOOT=yes第二行后追加TYPE=Ethernet:
[root@andrew Andrew]# sed ‘2a TYPE=Ethernet’ test.txt DEVICE=eno16777736BOOTPROTO=staticTYPE=EthernetIPADDR=192.168.0.1NETMASK=255.255.255.0
GATEWAY=192.168.0.254
ONBOOT=yes
第三行前追加TYPE=Network:
[root@andrew Andrew]# sed ‘3i TYPE=Network’ test.txt DEVICE=eno16777736BOOTPROTO=staticTYPE=NetworkIPADDR=192.168.0.1NETMASK=255.255.255.0
GATEWAY=192.168.0.254
ONBOOT=yes
将样本文件中的所有yes替换为no:
[root@andrew Andrew]# sed ‘s/yes/no/g’ test.txt DEVICE=eno16777736BOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0
GATEWAY=192.168.0.254
ONBOOT=no
以上大多数操作指令都依据行号定位操作对象(地址),如2a即第二行后追加。实际工作中,可能大多数情况你并不确定你要操作对象(地址)的行号,这时更多的会使用正则表达式确定操作对象(地址)。下面是使用正则表达式定位操作行的示例:
匹配到包含ONBOOT的行,并在其后添加TYPE=Ethernet:
[root@andrew Andrew]# sed ‘/ONBOOT/a TYPE=Ethernet’ test.txt DEVICE=eno16777736BOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0
GATEWAY=192.168.0.254
ONBOOT=yesTYPE=Ethernet
匹配GATEWAY开始的行,并删除该行:
[root@andrew Andrew]# sed ‘/^GATEWAY/d’ test.txt DEVICE=eno16777736BOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0
ONBOOT=yes
另外,我们的操作指令可以写入到脚本文件中,并通过sed的-f选项读取,脚本文件中的注释行是以#开始的行,如果#后面的字符为n,则屏蔽Sed程序的自动输出功能,等同于命令选项-n。创建一个sed脚本,内容如下:
[root@andrew Andrew]# cat sed.sh#This is a test sed command#脚本内容为匹配到空白行后,删除该行/^$/d对test.txt文件执行sed.sh脚本指令:
[root@andrew Andrew]# sed -f sed.sh test.txt DEVICE=eno16777736BOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0GATEWAY=192.168.0.254ONBOOT=yes
而当你需要执行多个指令时,可以使用以下三种方法:
(1)使用分号隔开指令
[root@andrew Andrew]# sed ‘s/yes/no/;s/static/dhcp/’ test.txt DEVICE=eno16777736BOOTPROTO=dhcpIPADDR=192.168.0.1NETMASK=255.255.255.0
GATEWAY=192.168.0.254
ONBOOT=no
(2)使用-e选项
[root@andrew Andrew]# sed -e ‘s/yes/no/’ -e ‘s/static/dhcp/’ test.txt DEVICE=eno16777736BOOTPROTO=dhcpIPADDR=192.168.0.1NETMASK=255.255.255.0
GATEWAY=192.168.0.254
ONBOOT=no
(3)利用分行
[root@andrew Andrew]# sed ‘
s/yes/no/s/static/dhcp/’ test.txtDEVICE=eno16777736BOOTPROTO=dhcpIPADDR=192.168.0.1NETMASK=255.255.255.0GATEWAY=192.168.0.254ONBOOT=no
然而在命令行上输入过长的指令是愚蠢的,这时需要使用-f选项指定sed脚本文件,在脚本文件中可以包含多行指令,而且也便于修改。
2.操作地址匹配范例
通过以上范例不难发现,我们编写的脚本指令需要指定一个地址来决定操作范围,如果不指定,则默认对文件的所有行进行操作。如:sed ‘d’ test.txt将删除test.txt的所有行,而‘2d’则仅删除第二行。Sed为我们提供了以下这些方式来确定需要操作地址的范围。
-number
指定输入文件的唯一行号
-first~step
指定以first开始,并指定操作步长为step,如1、2指定第一行、第三行、第五行……为操作地址。2~5指定第二行开始,每5行匹配一次操作地址
$
匹配文件的最后一行
/regexp/
//中间包含的是正则表达式,通过正则表达式匹配操作地址。如果//中正则表达式为空,匹配最近一次正则表达式的匹配地址,后面会有范例
\cregexpc
\c和c之间匹配正则表达式,c字符可以使用任意字符代替
addr1,addr2
匹配从操作地址1到操作地址2的所有行
addr1,+N
匹配地址1以及后面的N行内容
打印文件的奇数行:
[root@andrew Andrew]# cat -n test.txt 1 DEVICE=eno16777736 2 BOOTPROTO=static 3 IPADDR=192.168.0.1 4 NETMASK=255.255.255.0 5 6 GATEWAY=192.168.0.254 7 8 ONBOOT=yes[root@andrew Andrew]# sed -n ‘1~2p’ test.txt DEVICE=eno16777736IPADDR=192.168.0.1
删除2~8之间的所有行:
[root@andrew Andrew]# cat -n test.txt 1 DEVICE=eno16777736 2 BOOTPROTO=static 3 IPADDR=192.168.0.1 4 NETMASK=255.255.255.0 5 6 GATEWAY=192.168.0.254 7 8 ONBOOT=yes[root@andrew Andrew]# sed ‘2,8d’ test.txt DEVICE=eno16777736
四.Sed指令和脚本1.Sed常用指令汇总
下表给出了常用sed脚本指令的说明,下面分别看看每个指令的详细用法:
指令
功能
指令
功能
-s
替换
-d
删除
-a
追加
-i
插入
-c
更改
-l
打印(显示非打印字符)
-y
按字符转换
-L
打印(不显示非打印字符)
-p
打印
-r
读入文件内容
-w
保存至文件
-q
退出
2.部分指令详解
(1)替换指令(s,Substitution)
指令格式:[address]s/pattern/replacement/flags
address为操作地址,s为替换指令,/pattern/匹配需要替换的内容,/replacement为替换的新内容。Flags标记可以是:
Flags标记
含义
-n
1-512之间的数字,表示对模式空间中指定模式的第n次出现进行替换。如一行中有3个A,而只想替换第二个A。
-g
对模式空间的所有匹配进行全局更改。没有g则只有第一次匹配被替换,如一行中有3个A,则仅替换第一个A。
-p
打印模式空间的内容
-w file
将模式空间的内容写到文件file中
replacement为字符串,用来替换与正则表达式匹配的内容。在replace部分,只有下列字符有特殊含义:
&
用正则表达式匹配的内容进行替换
\n
匹配第n个子串,该子串之前在pattern中用\(\)指定
\
转义(转义替换部分包含:&、\等)
(2)删除指令(d,delete)
删除指令用于删除匹配的行,而且删除命令还会改变sed脚本中命令的执行顺序。因为匹配的行一旦删除,模式空间将变为“空”,自然不会再执行sed脚本后续的命令。删除命令将导致读取新的输入行(下一行),而sed脚本中的命令则从头开始重新执行。需要注意的是,删除时是删除整行,而不只是删除匹配的内容(如果删除匹配的内容,可以使用替换)
(3)转换指令(y)
按字符转换(Transform)的语法格式为:[address]y/source-chars/dest-chars,其中,[address]用来定位需要修改的行,source-chars为需要被修改的字符,dest-chars为准备替换的字符。
3.Sed脚本指令范例
(1)范例1
范例1所使用的样本文件为:
[root@andrew Andrew]# cat test.txt
Hello the World!
范例1:将样本文件中第二个替换为
编写sed脚本,替换与行匹配相同的内容,即将body替换为/body,但仅替换第二个body为/body。
[root@andrew Andrew]# cat sed.sh /body/{s//\/body/2}
执行sed程序的结果如下:
[root@andrew Andrew]# sed -f sed.sh test.txt
Hello the World!
(2)范例2
范例2使用的样本文件为:
[root@andrew Andrew]# cat test.txt
h1Helloh1h2Helloh2h3Helloh3
范例2:给所有第一个的h1,h2等添加,第二个h1,h2添加>.
编写sed脚本为:
[root@andrew Andrew]# cat sed.sh /h[0-9]/{s//&>/1s//\/&>/2}
说明:匹配h紧跟一个数字的行,替换与上一行中匹配内容相同的内容,即将h[0-9]替换为,其中&为前面要替换的内容。第一条s替换指令仅替换第一个h1,h2…,第二条s替换指令用来替换第二个h1,h2…
执行sedc程序的结果如下:
[root@andrew Andrew]# sed -f sed.sh test.txt
Hello
Hello
Hello
技巧:关于‘s///’命令的另一个妙处是:‘/’分隔符有许多替换方案,如果规则表达式或替换字符串中有许多斜杠,则可以通过在‘s’之后指定一个不同的字符来更改分隔符。示例:sed -e ‘s:/usr/local:/usr:g’ mylist.txt此时是替换分隔符,sed会将/usr/local替换为/usr.
(3)范例3
范例3所使用的样本文件为(注意有空白行):
[root@andrew Andrew]# cat test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=static
IPADDR=192.168.0.1NETMASK=255.255.255.0GATEWAY=192.168.0.254
范例3:删除文件中的空白行。
编写sed脚本为:
[root@andrew Andrew]# cat sed.sh /.*/{/^$/d}
执行sed程序的结果如下:
[root@andrew Andrew]# sed -f sed.sh test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0GATEWAY=192.168.0.254
(4)范例4-范例6
范例4-范例7所使用的样本文件为:
[root@andrew Andrew]# cat test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=staticNETMASK=255.255.255.0GATEWAY=192.168.0.254
范例4:在static行后添加一行,内容为IPADDR=192.168.0.1。
[root@andrew Andrew]# sed ‘/static/a IPADDR=192.168.0.1’ test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0GATEWAY=192.168.0.254
范例5:在匹配NETMASK的行前插入内容IPADDR=192.168.0.1。
[root@andrew Andrew]# sed ‘/NETMASK/i IPADDR=192.168.0.1’ test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=staticIPADDR=192.168.0.1NETMASK=255.255.255.0GATEWAY=192.168.0.254
范例6:将包含ONBOOT行的内容更改为ONBOOT=no
[root@andrew Andrew]# sed ‘/ONBOOT/c ONBOOT=no’ test.txt DEVICE=eno16777736ONBOOT=noBOOTPROTO=staticNETMASK=255.255.255.0GATEWAY=192.168.0.254
(5)范例7和范例8
范例7和范例8所使用的样本文件为:
[root@andrew Andrew]# cat test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=staticnetmask=255.255.255.0GATEWAY=192.168.0.254
范例7:将小写转换为大写
编写sed脚本为:
[root@andrew Andrew]# cat sed.sh /.*/{/netmask/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/}
执行sed程序的结果如下:
[root@andrew Andrew]# sed -f sed.sh test.txt DEVICE=eno16777736ONBOOT=yesBOOTPROTO=staticNETMASK=255.255.255.0GATEWAY=192.168.0.254
范例8:显示第一、第二行的内容
打印(p):作用类似于l(列印),但不显示非显示字符,一般与-n配合使用
[root@andrew Andrew]# sed -n ‘1,2p’ test.txt DEVICE=eno16777736ONBOOT=yes
(6)范例9和范例10
范例9和范例10所使用的样本文件为:
[root@andrew Andrew]# cat name.txt JacobTomJerry[root@andrew Andrew]# cat mail.txt jacob@gmail.comtom@gmail.comjerry@gmail.com
范例9:先读取name.txt文件内容,再读取mail.txt文件内容。
编写sed脚本为:
[root@andrew Andrew]# cat sed.sh /.*/{$r mail.txt}
执行sed程序的结果如下:
[root@andrew Andrew]# sed -f sed.sh name.txt JacobTomJerryjacob@gmail.comtom@gmail.comjerry@gmail.com
范例10:显示name.txt内容的前两行内容后退出sed指令。
[root@andrew Andrew]# sed ‘2q’ name.txt JacobTom
五.Sed高级应用正常的Sed数据处理流程是读取文档的一行至模式空间,然后对该行应用相应的Sed指令,当指令完成后输出该行并清空模式空间,依次循环读入文档的下一行数据,直至文档数据结尾。然而在真实环境中的数据可能不会那么有规律,有时我们会把数据分多行写入文档,如:
姓名:张三,邮箱:zhangsan@gmail.com姓名:李四,邮箱:lisi@gmain.com从上面的模板文件中可以看出,实际上每两行为一条完整的记录,而此时如果需要使用Sed对该文档进行处理,就需要对Sed工作流程进行人工干预。
1.多行操作Next
Next(N)指令通过读取新的输入行,并将它追加至模式空间的现有内容之后,来创建多行模式空间。模式空间的最初内容与新的输入行之间用换行符分割。在模式空间中插入的换行符可以使用\n匹配。
范例1:使用的样本文件为:
[root@andrew Andrew]# cat test.txt Name:TomMail:Tom@gmail.comName:JerryMail:Jerry@gmail.com编写Sed指令脚本如下(读取样本文件内容至模式空间,当读取的内容与Name匹配时,立刻读取下一行内容,再输出模式空间中的内容,#n用来屏蔽自动输出)。
[root@andrew Andrew]# cat sed.sh #n/Name/{NL}
运行脚本结果如下:
[root@andrew Andrew]# sed -f sed.sh test.txt Name:Tom Mail:Tom@gmail.comName:Jerry Mail:Jerry@gmail.com
范例2:使用的样本文件为:
[root@andrew Andrew]# cat test.txt 111222222222333
编写Sed指令脚本(读取样本文件内容至模式空间,当读取的内容与222匹配时,立刻读取下一行内容,再输出模式空间中的内容,小写的l会打印非打印字符)。
[root@andrew Andrew]# cat sed.sh #n/222/{Nl}运行脚本结果如下:
[root@andrew Andrew]# sed -f sed.sh test.txt 222\n222
2.多行操作Print
Print(P)即多行打印P,它与打印p稍有不同,前者仅输出多行模式空间中的第一部分,直到第一个插入的\n换行符为止。综合范例所使用的样本文件为:
[root@andrew Andrew]# cat test.txt aaabbbcccdddeeefff下面通过多条sed命令对比不同打印方式的差别,输出结果如下所示:
[root@andrew Andrew]# sed ‘/.*/N’ test.txt aaabbbcccdddeeefff
[root@andrew Andrew]# sed ‘/.*/N;L’ test.txt aaa bbbaaabbbccc dddcccdddeee fffeeefff
[root@andrew Andrew]# sed ‘/.*/N;P’ test.txt aaaaaabbbccccccdddeeeeeefff
[root@andrew Andrew]# sed ‘/.*/N;p’ test.txt aaabbbaaabbbcccdddcccdddeeefffeeefff第一个sed命令使用了N读取下一行,新读取的内容与原有内容直接使用\n分隔。但sed读取下一行后没有任何后续指令,所以sed自动输出,即输出源文件的所有内容。
第二个sed命令使用了N读取下一行,L表示显示模式空间的内容,即aaa bbb,同时sed命令的自动输出功能会把源文件内容显示出来,即aaa,bbb。以此类推,sed继续读取第三行ccc,并使用N将ddd追加至行尾,使用L显示模式空间的内容(不显示非打印字符),sed自动输出后再把源文件内容显示出来。
第三个sed命令使用N将下一行追加至行尾,现在模式空间中的内容为aaa\bbb,而P指令的作用是打印模式空间中的第一部分内容直到\n结尾,即仅打印aaa,这时sed的自动输出功能输出aaa,bbb(sed自动输出会将\n输出为换行)。依次类推,读取第三行ccc,N将ddd追加至行尾,P打印\n前的内容,同时sed命令也将自动输出。
第四个sed命令的原理类似于第三个sed命令,但p打印时,\n看作回车换行,所以打印出来的是aaa回车bbb.
3.多行删除操作Delete(D)
指令d为删除命令,其作用是删除模式空间中的内容并读入新的输入行,而如果sed在d指令后还有多条指令,则余下的指令将不再执行,而是返回第一条指令对新读入行进行处理。而多行删除指令D将删除模式空间中直到第一个插入的换行符(\n)前的这部份内容,它不会读入新的输入行,并返回sed脚本的顶端,使得剩余指令继续应用于模式空间中剩余的内容。
4.Hold(h,H),Get(g,G)
我们知道,模式空间是存放当前输入行的缓冲区。除此之外,Sed还有一个称为保持空间(hold space)的缓冲区。模式空间的内容可以复制到保持空间,保持空间的内容同样可以复制到模式空间,有一组Sed命令用于在两者之间移动数据。
Hold(h|H)
将模式空间的内容复制或追加到保持空间
Get(g|G)
将保持空间的内容复制或追加到模式空间
Exchange(x)
交换保持空间与模式空间的内容
保留空间范例所使用的样本文件如下:
[root@andrew Andrew]# cat test.txt aaabbbcccddd[root@andrew Andrew]# cat sed.sh /aaa/{hd}/ccc/{G}[root@andrew Andrew]# sed -f sed.sh test.txt bbbcccaaaddd
以上就是为各位朋友分享的相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多等着你!