文本处理工具有好多种,上次介绍了grep,这次介绍一下sed。sed全名stream editor,意为行编辑器,或者流编辑器。Sed是逐行进行编辑的,下面介绍常规用法和高级用法。
格式:sed [option] 'script' inputfile sed加选项,单引号里是要执行的一些操作,后面跟操作的对象,常常是文件或者脚本文件。
一、选项
-n 不输出模式空间内容到屏幕,即不自动打印
-e: 多点编辑,对每行处理时,可以有多个Script
-f: 把Script写到文件当中,在执行sed时-f 指定文件路径,如果是多个Script,换行写
-r: 支持扩展的正则表达式
-i: 直接将处理的结果写入文件
-i文件名 在将处理的结果写入文件之前备份一份
上面这些选项常常用作地址定界,下面举例说明它们的用法。
-
不给地址:对全文进行处理
sed ' ' 这里没有给定具体范围,输入什么就输出什么,sed默认打印输出,如在屏幕输入a,回车之后默认输出a,相当于输出两遍
sed -n ' '这里加-n就是把默认输出到屏幕的给去掉,不显示默认值,如在屏幕输入a,就会打印a,但是不显示默认的,所以相当于输出一遍
-
单地址:
先给个文件供参考:
假如上面的是文件a.txt的内容,下面基于这个内容来做实验。
sed '2p' a.txt 这里2的意思是第二行,p的意思是打印输出,这就话就是说把名为a.txt的文件的第二行的内容打印输出到屏幕,但是由于sed默认会打印一遍,所以结果是第二行输出了两遍。
sed -n '2p' a.txt 和上面的差不多,但是这里加了-n,-n就是不输出默认的,所以这里意思就是只显示第二行的内容
sed -n '/a/p' a.txt 这里也是一个单地址界定,/a/意思就是取有字母a的行 ,这个命令的意思就是把有a的行打印出来
-
地址范围:
sed '2,3p' a.txt 这里2,3的意思就是一个范围定界啦,意为2到3行,p是打印输出,所以这个命令的意思就是把2到3行的内容打印出来,这里默认没有去掉,所以会把所有的都打印一遍,然后2到3行的会多打印一遍。
sed -n '2,3p' a.txt 和上面的意思一样,加-n意思就是只打印2到3行,其他的不输出
sed -n '2,+1p' a.txt 这里'2,+1p'意思是输出2到2+1行的内容,也就是第二行到第三行的内容,和上面意思差不多,只不过换了一种表示方法。
sed -n '/dog/,/mouse/p' b.txt '/dog/,/mouse/p'意思是把有dog的行到有mouse的行的内容截取出来
先看一下b.txt的内容
再看运行命令的结果
sed -n '2,/desk/p' c.txt '/2,/desk/p' 意思是把第二行到有desk的行的内容输出出来
先看一下c.txt的内容
运行上面的命令后结果为
-
~步进
sed -n '1~2p' c.txt '1~2p'意思就是输出奇数行的内容 ,若第一个为1,第二个就为3,第三个就是5,一次加2,所以整体的意思就是输出1,3,5,7,…..行的内容了。
二、编辑命令
d: 删除模式空间匹配的行,并立即启用下一轮循环
举例:sed '2d' d.txt '2d'就是把第二行的内容从文件中删除
p:打印当前模式空间内容,追加到默认输出之后
举例: sed -n '2p' d.txt '2p'输出第二行的内容,加-n,只输出第二行的内容
a [\]text:在指定行后面追加文本,支持使用\n实现多行追加
举例:sed '2a\123' c.txt '2a\123' 就是在第二行的后面加上一行内容为123
i [\]text:在行前面插入文本
举例:sed '2i\123' c.txt '2i\123'就是在第二行的前面加上一行内容为123
c [\]text:替换行为单行或多行文本
举例:sed '2c\123' c.txt '2c\123' 就是把第二行的内容替换为123
w /path/somefile: 保存模式匹配的行至指定文件
举例:sed '2w/root/bin/pets' d.txt '2w/root/bin/pets' 意思就是把第二行的内容保存到/root/bin/pets,w就是写的意思
r /path/somefile:读取指定文件的文本至模式空间中匹配到的行后
举例:sed '2r/root/s.txt' d.txt '2r/root/s.txt'意思就是把文件s.txt的内容保存到d.txt的第二行的后面,r就是读的意思
=: 为模式空间中的行打印行号
举例:sed '=' c.txt 意思就是给文件c.txt每行打上行号
!:模式空间中匹配行取反处理
举例:sed -n '2!p' d.txt '2!p'意思就是不显示第二行,其他的都输出,加上-n就是不显示默认,总的意思就是显示文件内容一遍,除了第二行。
s///:查找替换,支持使用其它分隔符,s@@@,s###替换标记:
g: 行内全局替换
举例:sed 's/dog/miaomiao/g' c.txt 把文件c.txt中的dog替换成miaomiao,g是全局替换。
三、日常练习
1、删除centos7系统/etc/grub2.cfg文件中所有以空白开头的行行首的空白字符
解题思路 :sed 是 支持正则表达式的,所以在这里可以引用。Sed –r 就是支持扩展正则表达式,^[[:space:]]是以空白开头,在这里可以使用替换思想,把以空白开头的替换为无,就相当于删除了空白 ,所以本题使用替换的方法。
答:cat /etc/grub2.cfg |sed -r 's/^[[:space:]]+//'
2、删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符
解题思路:和第一题思路很像,^#就是以#开头,[[:space:]]+就是至少一个空白字符,+就是至少一个的意思,在扩展正则表达式中,不用加\,本题同样采用替换的思想,把以#开头,后面….替换为无就可以了,相当于删除了。
答:cat /etc/fstab|sed -r 's/^#[[:space:]]+//'
3、在centos6系统/root/install.log每一行行首增加#号
解题思路:^就代表行首的意思,使用替换思想,把行首替换为#就是本题解题思路。
答题:cat /root/install.log|sed 's/^/#/'
4、在/etc/fstab文件中不以#开头的行的行首增加#号
解题思路:^[^#]表示以非#开头的,也就是不以#开头,#&就是增加#的意思,这里使用了后向引用和替换的思想。
答题:cat /etc/fstab |sed 's/^[^#]/#&/'
5、处理/etc/fstab路径,使用sed命令取出其目录名和基名
解题思路:使用替换思想,可以看到目录名就是/etc/,就是以/开头的,最后跟着个/的,所以在这里我们就先把目录名给提取出来,^/.*/意思就是以/开头,中间有任意内容,后面有/,下面提取基名,可以看到基名是不以/开头的,但可以以/结尾的,所以这里就是[^/].*/?$,[^/]不以/开头,.*任意内容,/?$以0或者一个/结尾,我们把基名和目录名已经截取出来了,接着使用后向引用,就可以直接提取基名和目录名了。\1引用第一个括号中的内容,\2引用第二个括号里的内容。
答题:echo /etc/fstab |sed -r 's#(^/.*/)([^/].*/?$)#\1\n\2#'
四、高级编辑命令
前面都是一些简单的选项和命令,现在来点有难度的。Sed高级编辑命令如下:
h: 把模式空间中的内容覆盖至保持空间中
H:把模式空间中的内容追加至保持空间中
g: 从保持空间取出数据覆盖至模式空间
G:从保持空间取出内容追加至模式空间
x: 把模式空间中的内容与保持空间中的内容进行互换
n: 读取匹配到的行的下一行覆盖至模式空间
N:读取匹配到的行的下一行追加至模式空间
d: 删除模式空间中的行
D:删除当前模式空间开端至\n的内容(不再传至标准输
出),放弃之后的命令,但是对剩余模式空间重新执行sed
举例说明:
-
sed -n 'n;p' FILE
解释:n读取匹配到的行的下一行覆盖至模式空间, p输出。意思就是开始读第一行内容到模式空间,然后第二行内容把第一行内容覆盖掉,输出第二行,然后读第三行内容到模式空间,再然后第四行内容把第三行内容覆盖,输出第四行,后面依次循环,可以想到输出的都为偶数行,所以这条命令的意思就是输出偶数行。
如下所示:输入7个数字,结果只输出了2,4,6,都是偶数。
-
sed '1!G;h;$!d' FILE
解释:1!当不是第一行的时候,G从保持空间取出内容追加至模式空间,h把模式空间中的内容覆盖至保持空间中,$!不是末尾的时候,d删除,这些命令连起来就是说 先看是不是第一行,是的话跳过第一个分号,执行第二个分号命令,不是的话就从保持空间取出内容追加至模式空间,现在先说从第一行执行的过程,首先判断是第一行,然后跳过第一个分号,执行第二个分号内容h,假设第一行数据为1,h执行后模式1覆盖到保持空间,同时模式空间还有1,记住,是覆盖而不是转移,接着执行第三个分号内容,1肯定不是结尾,所以执行删除命令,把模式空间中的1删除,现在只剩保持空间还有一个1,第一遍循环已经结束,接着执行第二遍循环,多都市一样的,这里我就不多说了,相信大家自己会判断的。这条命令的意思就是逆序输出。
如下所示:
-
sed -n '1!G;h;$p'
解释:先判断是否为第一行,是的话跳过第一个分号,执行第二个分号的命令,不是的话从保持空间取出内容追加至模式空间,接着依次往下执行,h把模式空间中的内容覆盖至保持空间中,$p判断时是否为结尾,是的话输出。这条命令意思也是逆序输出。
如下所示
-
seq 7 |sed 'n;d'
解释:n读取匹配到的行的下一行覆盖至模式空间,d删除,先把第一行内容输出到模式空间,然后读取第二行内容,接着执行d把第二行的内容删除,输出第一行内容到屏幕,接着读取第三行内容到模式空间,读取第四行内容,再把第四行内容删除,后面依次循环,可以想到输出到屏幕的是1,3,5,….奇数行,所以这条命令的意思就是输出奇数行。
如下所示: