4.2 sed:流编辑器
4.2.1 sed命令语法及参数说明
【命令星级】 ★★★★★
【功能说明】
sed是Stream Editor(字符流编辑器)的缩写,简称流编辑器。它是Linux三剑客之一。
sed是操作、过滤和转换文本内容的强大工具。sed的常用功能包含对文件实现快速增删改查(增加、删除、修改、查询),其中查询的功能中最常用的两大功能是过滤(过滤指定字符串)和取行(取出指定的行)。
【语法格式】
sed [选项] [sed内置命令字符] [输入文件]
说明:
1)为了避免混淆,本文称呼sed为sed或sed命令,将实现不同sed功能的内部命令参数,称为“sed内置命令字符”,以区别是sed命令还是sed内置命令选项。
2)“sed内置命令字符”既可以是单个命令,也可以是多个命令参数的组合。
3)“输入文件”为sed需要处理的文件,是可选项,sed还能从标准输入(如管道)获取输入。
【选项说明】
表4-2针对sed命令的参数选项进行了说明。
表4-2 sed常用参数选项
sed内置命令字符可用来实现对文件的不同操作功能,例如对文件的增删改查等,表4-3为sed的内置命令字符说明。
表4-3 sed的常用内置命令字符功能说明
4.2.2 使用范例
4.2.2.1 基础范例
为了更好地测试sed命令的用法,准备测试的内容及文件如下:
[root@centos7 ~]# cat >persons.txt<<EOF
> 101,netealge,CEO
> 102,zhangyao,CTO
> 103,Alex,COO
> 104,yy,CFO
> 105,feixue,CIO
> EOF #这里要敲回车才能结束,另外,EOF必须成对出现,但也可以用别的成对标签来替换。例如:neteagle字符标签。
**范例4-10:**在文件指定行后追加文本。
[root@centos7 ~]# sed '2a 106,dandan,CSO' persons.txt #这里使用了sed内置命令a追加功能。
101,netealge,CEO
102,zhangyao,CTO
106,dandan,CSO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
命令详细说明:
首先我们来看一下命令执行后的结果,可以看到在第二行"102,zhangyao,CTO"后面追加了一行新的文本“106,dandan,CSO”。
接下来我们解读一下该sed命令语句的结构,sed开头,然后接上空格,这里要郑重地和大家说一点,在练习Linux命令时一定不要忘了空格(空格个数不限,但至少要有一个!),Linux命令和各个参数之间都需要以空格作为分隔符,否则命令会无法执行。
在空格后面,我们先输入一对单引号(‘’),然后再退一格在单引号中输入sed的内置命令字符,先把2个引号输入完了再在里面填写内容,这也是一格良好的习惯,因为很多人在输入内容的时候把后面的引号忘了,最后命令执行失败还不知道哪里错了,因此我们要养成良好的习惯,以避免没有意义的错误。
接下来所讲的是重点了,新手们,一定要记好!
-
sed后面单引号中的内容为:2a 106,dandan,CSO。
-
2表示对第2行进行操作,其他的行忽略。
-
a表示追加,2a即在第2行后追加文本。
-
2a后面加上空格,然后接着输入想要追加的文本内容(106,dandan,CSO)即可。
**范例4-11:**在文件指定的行前加入文本。
[root@centos7 ~]# sed '2i 106,dandan,CSO' persons.txt #这里使用了sed内置命令i插入功能。 101,netealge,CEO 106,dandan,CSO 102,zhangyao,CTO 103,Alex,COO 104,yy,CFO 105,feixue,CIO
命令详细说明:
首先我们来看一下上述命令的执行结果,可以看到命令执行后在原来的第二行"102,zhangyao,CTO"前面插入了新的一行为“106,dandan,CSO”,原来的第2行变成了第3行了。
接下来我们解读一下该sed命令语句的结构,以sed开头,然后接上空格,在空格后面,是一对单引号(‘’),然后再单引号中的内容是“2i 106,dandan,CSO”。
-
2表示对第2行进行操作,其他的行可忽略。
-
i代表插入的意思,2i表示在第2行即当前行插入文本,即插入到第二行。
-
2i后面加上空格,然后跟上要插入的文本(106,dandan,CSO),最后接上要处理的文件persons.txt。
**范例4-12:**在文件指定行后追加多行文本。
[root@centos7 ~]# sed '2a 106,dandan,CSO\n107,bingbing,CCO' persons.txt 101,netealge,CEO 102,zhangyao,CTO 106,dandan,CSO 107,bingbing,CCO 103,Alex,COO 104,yy,CFO 105,feixue,CIO
命令详细说明:
首先我们粗略看一下该命令语句,可以发现命令结构与单行增加文本几乎是没有区别的。
然后我们看一下命令的结果,可以看到原来的第二行“102,zhangyao,CTO”后面追加了2行文本“106,dandan,CSO”和“107,bingbing,CCO”。
接下来我们解读一下该sed命令语句的结构,sed软件大头,然后接上空格,在空格后面,我们先输入一对单引号(‘’),然后退一格在单引号中的内容是’2a 106,dandan,CSO\n107,bingbing,CCO’。
-
2代表指定对第2行进行操作,其他的行忽略。
-
a代表追加的意思,2a即在第2行后追加文本。
-
2a后面加上空格,然后输入想要插入的多行文本即可。这里的每行文本都使用“\n”连接就可以写成一行了。最后输入想要处理的文件persons.txt
同理,在文件指定行前插入多行文本只需要将本例的sed内置命令a换成i就可以了。
**范例4-13:**删除文件中一行指定的文本。
[root@centos7 ~]# sed '2d' persons.txt #这里使用了sed内置命令d实现删除功能,指定删除第2行的文本。
101,netealge,CEO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
**范例4-14:**删除文件中指定的多行文本。
[root@centos7 ~]# sed '2,5d' persons.txt #“2,5”是一个数字地址的组合,用逗号作为分隔,其作用是删除文件的第二行到第五行(删除多行)文本,包括第2行和第5行,因此只剩下第1行。
101,netealge,CEO
**范例4-15:**使用sed命令替换文本内容。
[root@centos7 ~]# sed 's#zhangyao#dandan#g' persons.txt #这里使用了sed内置命令s来实现替换功能,并且使用了全局替换标志g表示替换文件中匹配zhangyao的所有字符串。需要注意一下语法格式,将需要替换的文本“zhangyao”放在第一个和第二个“#”之间,将替换后的文本“dandan”放在第二个和第三个“#”之间。结果为第二行的“zhangyao”替换为“dandan”。
101,netealge,CEO
102,dandan,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
**范例4-16:**打印输出文件的指定行的内容。
[root@centos7 ~]# sed '2p' persons.txt #这里使用了sed内置命令p实现查询功能,并结合数字地址指定查询第2行的内容,但是我们会发现结果不只是输出第2行,文件的其他内容也显示出来了,这是因为sed命令有一个默认输出的功能。
101,netealge,CEO #默认输出的行。
102,zhangyao,CTO #p命令输出的行。
102,zhangyao,CTO #默认输出的行。
103,Alex,COO #默认输出的行。
104,yy,CFO #默认输出的行。
105,feixue,CIO #默认输出的行。
[root@centos7 ~]# sed -n '2p' persons.txt #为了解决上面命令显示多余内容的问题,使用选项-n取消默认输出,只输出匹配行的文本,因此大家只需要记住使用命令p必用选项-n。
102,zhangyao,CTO
[root@centos7 ~]# sed -n '2,3p' persons.txt #当然使用地址范围“2,3”能够查看第2行到第3行的内容。
102,zhangyao,CTO
103,Alex,COO
4.2.2.2 生产案例
**范例4-17:**优化SSH配置(在SSH服务的配置文件中增加多行参数)。
在学习CentOS系统的优化时,有一个优化点:更改ssh服务远程登录的配置。主要的操作是在ssh的配置文件/etc/ssh/sshd_config中加入下面5行文本。
Port 52113
PermitRootLogin no
PermitEmptyPasswords no
UseDNS no
GssAPIAuthentication no
当然我们可以使用vi/vim命令编辑这个文本,但这样会比较麻烦,现在想用一条命令增加上述5行文本到第13行前。
**注意:**修改前别忘了备份配置文件:cp /etc/ssh/sshd_config{,.ori}。
[root@centos7 ~]# sed -i.bak '13i Port 52113\nPermitRootLogin no\nPermitEmptyPasswords no\nUseDNS no\nGssAPIAuthentication no' /etc/ssh/sshd_config #这道题用到了范例4-3的方法,将插入的5行内容使用“\n”就可以变成一行了。题目要求在第13行前面插入,因此这里使用sed内置命令i。i后面接字符,表示备份文件后再处理,例如:-i.bak,是先把/etc/ssh/sshd_config文件备份为/etc/ssh/sshd_config.bak后,再处理文件。
上面执行的命令出现了一个新的选项“-i”,这个选项的作用是能够实际修改文件的内容,可能读者也发现了前面几个例子操作完命令之后,文件的内容并没有发生变化,这是因为sed命令默认操作的是内存中的数据,如果想要真正地修改文件的内容,就需要使用选项“ -i”将修改写到磁盘文件上。
[root@centos7 ~]# sed -n '13,17p' /etc/ssh/sshd_config #查看文件的第13行到第17行,确认修改成功。
Port 52113
PermitRootLogin no
PermitEmptyPasswords no
UseDNS no
GssAPIAuthentication no
[root@centos7 ~]# rm -f /etc/ssh/sshd_config
[root@centos7 ~]# mv /etc/ssh/sshd_config.bak /etc/ssh/sshd_config
**范例4-18:**通过Shell脚本生成的账号密码如下所示。
[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8 #生成8位随机数。
BhmksfZA[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8
jP2sJu5s[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8
APE6F0e6[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8
ziYCdEBq[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8
5hHUFlQ8[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8
LfP8L5fa[root@centos7 ~]# cat /dev/urandom | tr -dc '[:alnum:]' | head -c8
Pqk8nA89[root@centos7 ~]# cat >test.txt<<EOF #创建测试文件。
> stu10309
> BhmksfZA
> stu10312
> jP2sJu5s
> stu10315
> APE6F0e6
> stu10318
> ziYCdEBq
> sut10321
> 5hHUFlQ8
> stu10324
> LfP8L5fa
> stu10327
> Pqk8nA89
> EOF
[root@centos7 ~]# cat test.txt
stu10309 #账号。
BhmksfZA #密码。
stu10312
jP2sJu5s
stu10315
APE6F0e6
stu10318
ziYCdEBq
sut10321
5hHUFlQ8
stu10324
LfP8L5fa
stu10327
Pqk8nA89
现在要求使用命令将上面的文本转换成下面SVN服务配置文件中的账号及密码格式。
stu10309=BhmksfZA #格式“账号=密码”。
stu10312=jP2sJu5s
stu10315=APE6F0e6
stu10318=ziYCdEBq
sut10321=5hHUFlQ8
stu10324=LfP8L5fa
stu10327=Pqk8nA89
**提示:**实现的思路就是将奇数行和偶数行用“=”(等号)连接成一行。
解答:此题利用了sed的特殊功能应用。
[root@centos7 ~]# sed 'N;s#\n#=#g' test.txt
stu10309=BhmksfZA
stu10312=jP2sJu5s
stu10315=APE6F0e6
stu10318=ziYCdEBq
sut10321=5hHUFlQ8
stu10324=LfP8L5fa
stu10327=Pqk8nA89
命令详细说明:
sed内置命令N的作用:不会清空模式空间内容,并且从输入文件中读取下一行数据,追加到模式空间中,两行数据以换行符\n连接。
第一行是“stu10309”存入模式空间,碰到命令“N”,读取第二行“BhmksfZA”,此时模式空间内容为“stu10309\nBhmksfZA”;然后执行“s#\n#=#g”将“\n”替换为“=”,即为“stu10309=BhmksfZA”,输出到平面上,第一个循环结束;后面的循环和前面的思路一样,直到文件结束,更多细节请参考本书sed命令部分。