跳转至

13.Shell三剑客之sed

1 Sed概述

1.1 Sed是什么

Sed全名为Stream EDitor,顾名思义是对数据流进行编辑操作的一个命令,它能够遍历文件或文件流,对读入的输入流可以将其先存储在模式空间中,并将行号记录在内存中,利用模式空间中的一系列指定命令对其进行操作,待操作完成后从模式空间输出到stdout,类似于在一个管道在其中对数据进行加工,完成后从另一头输出,接着读取下一行,重复往返,直至将所有标准输入读取处理完成。

1.2 为什么用Sed

Sed相较于grep/awk,其主要功能为对文件进行修改处理,可以对文件或标准输入数据流进行增删改查等操作,尤其适用于大文件或有规律的文件,利用此工具,能够帮助我们快捷的在编写Shell脚本中得心应手的对文件进行操作。

2 Sed的适用场景

  • 超大文件处理;

  • 有规律的文本,例如格式化后的日志文件等;

  • 对文件进行批量增加,替换等。

3 Sed的处理模式

Sed对输入的一行数据进行处理的模式,对整个文件进行重复执行此模式处理,在此说明对输入的一行数据处理的内在机制如下图所示:

  1. 首先读入文件流的一行到模式空间;

  2. 在模式空间内,对内容进行模式匹配处理;

  3. 输出处理后的数据内容;

  4. 清空当前模式空间;

  5. 读取第二行输入流到模式空间;

  6. 又开始对模式空间内的下一行输入数据进行处理。

4 语法详解

sed语法格式如下图所示:

sed [option] 'address command' [file ]

sed的语法格式主要分为四个字段,options选项,引号内有地址定界/命令,以及要处理的文件,接下来让我们详细讲解每一个语法字段,更全面的认识sed这个脚本利器。

4.1 options:

选项为可选,利用它来为sed指定一些处理方式,主要的有如下:

  • -n:静默模式,我们知道sed默认处理完模式空间后将内容输出到标准输出,利用这个这个参数仅显示script处理后的结果,不再默认显示模式空间中的内容,例如:打印/etc/passwd的地三行
[root@shell workspace]# sed -n '3p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin

在此直接指定地址定界3,然后command为p打印输出,由于不想输出/etc/passwd的全部内容,因此添加了-n选项。

* -e:<script>或--expression=<script> 以选项中指定的script来处理输入的文本文件,可以同时执行多个脚本;
* -f:对制定的文件直接进行sed的command操作;
* -i:直接修改原文件,我们都知道sed默认不对文件进行修改,只是读入一行到模式空间中,处理完成后输出,此参数为也直接修改了源文件;
* -r:支持扩展正则表达式,而不是使用默认的基础正则表达式。类比grep命令的egrep,更加快捷简洁的使用扩展正则表达式,因为有些元字符不用再使用反斜线"\\"了。

4.2 address:

地址定界用来指定读入文件的边界或步长。

  • startline,endline:指定读入文件的开始行于结束行号。
  • /regexp/:利用正则表达式匹配到的行进行处理,例如:打印/etc/passwd从以root开始到sync结束的内容
[root@shell workspace]# sed -n '/^root/,/^sync/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync

在此利用了匹配元字符^用来匹配行首,此内容在正则表达式中已经进行了详细解释。

  • /pattern1/,/pattern2/:第一次被pattern1匹配到的行开始,直到被pattern2匹配到的行结束,例如:打印/etc/passwd的第四行到第七行的内容
[root@shell workspace]# sed -n '3,7p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
  • linenuber:直接指定行号,需要处理哪一行。
  • startline,+n:从那一行开始,往后n行结束,例如:打印/etc/passwd的从第三行开始往后的2行的内容
[root@shell workspace]# sed -n "3,+2p" /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • startline~step:指定步长,每隔step步进行处理,常用在奇偶数处理,例如:打印奇数行
seq 10 |sed -n '1~2p'

seq来输出以数字为内容的10行,然后利用~2作为步长打印输出。

4.3 command:

具体对指定的文件进行怎样的处理,例如对模式空间内的内容进行增删改查具体的操作。

4.3.1 增

  • i:insert,在制定或匹配到的行前面添加新行内容为string,i\string, 为/etc/passwd 中的第一行前面添加一行内容为"####",例如:
[root@shell workspace]# sed '1i####' /etc/passwd
####
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....
  • a:append,在指定或匹配到的行后面追加新行,内容为string,a\string。 为/etc/passwd的第一行后面添加内容"aaa",例如:
[root@shell workspace]# sed '1a###' /etc/passwd
root:x:0:0:root:/root:/bin/bash
###
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

4.3.2 删

  • d:delete,删除符合地址定界条件的的行

删除/etc/inittab文件中注释行,例如:

sed '/^#/d' /etc/inittab

直接利用元字符匹配铆定以#开头的行进行删除操作,注意此处没有直接修改文件,如果添加-i选项,则直接对源文件进行修改,一般需要先备份,然后操作以免误操作原始文件。

4.3.3 改

  • s:s/pattern/string/修饰符: 查找并替换,默认只替换每行中第一次被模式匹配到的字符串 ,如果修饰符为g,则为全部替换。 替换/etc/passwd中的root为大写,例如:
[root@shell workspace]# sed 's/root/ROOT/g' /etc/passwd
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...

替换/etc/inittab文件中"id:3:initdefault:"一行中的数字为5,例如:

sed 's/id:[0-9]/id:5/g' /etc/inittab

在此利用元字符匹配[0-9]的一个数字进行替换为id:5

4.3.4 查

  • p:print,默认sed对模式空间内的处理完毕后,将输出的结果输出在标准输出,添加p命令,相当于输出了原文,又一次输出了模式匹配处理后的内容。

打印/etc/passwd的第三行,指定行号,例如:

[root@shell workspace]# sed -n '3p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin

在此直接指定地址定界3,然后command为p打印输出,由于不想输出/etc/passwd的全部内容,因此添加了-n选项。

5 实例

5.1 需求

目前腾讯云服务器Ubuntu版本用户为ubuntu用户,现又1000台服务器需要去开启root远程登录。

5.2 思路

开启ubuntu服务器的远程登录即修改其的/etc/ssh/sshd_config 文件的prohibit-password为yes即可,重启sshd服务即可,利用脚本逻辑处理。

5.3 实现

核心利用sed代码:

if [ ${ostype} == 'Ubuntu' ];then
    sed -i 's/prohibit-password/yes/g' /etc/ssh/sshd_config
    # 重启ssh服务
    service sshd restart
    [ $? -eq 0] && echo "${OSTYPE} sshd 开启成功" >>${LOG_FILE}
fi

6 注意事项

  • sed中利用于正则表达式配合可以得到1+1大于二的效果,配合使用功能更加丰富强大;
  • sed常用于修改文件,如果为查询文件可以利用grep,因为grep检索文件效率最高,如果为格式化输出建议使用awk;
  • sed在修改文件的时候尽可能先不要添加-i options,以免将源始文件修改异常难以恢复。

7 小结

sed的功能非常强大,它是我们shell编程中对文件修改不可或缺的利器,配合正则表达式常用来批量修改大文件,或有一定格式规律的文件,其还有很多高级功能。如果学有余力建议去man手册详细学习查看,在利用sed工具的时候需要时刻脑海中牢记求语法格式,万变不离其宗,遵循语法举一反三能够达到学生事半功倍的效果。