grep工具的功能其实还不够强大,grep实现的只是查找功能,而它却不能实现把查找的内容替换掉。以前用vim的时候,可以查找也可以替换,但是只局限于在文本内部来操作,而不能输出到屏幕上。sed工具以及后面要讲的awk工具就能实现把替换的文本输出到屏幕上的功能了,而且还有其他更丰富的功能。sed和awk都是流式编辑器,是针对文档的行来操作的。

先来创建一个目录 sed ,然后把目录 grep 里面的文件 passwd 拷贝过来,重命名为 test.txt ,见下图, 接着往下操作,sed 的语法很简单, 以上就是 sed 的用法,'/ /' 里面是要匹配的字符串,单引号后面加 p ,才会输出结果,但是 p 会把所有内容都显示出来,而目标行会特别的显示两行相同的内容出来。不想全部的内容都显示出来的话,需要在 sed 后面加上 -n ,这样就可以只显示目标行了。 sed 同时也支持 . 和 * (星),见下图, . 和 * (星)使用起来和 grep 相同,视觉上看起来麻烦一点。sed 还支持 + 号,见下图, 不想要脱义的时候,加上 -r 选项就可以。接着演示一些其他选项的用法,见下图, 上图用法同 grep 相似,这边就不赘述。 '2' 表示第二行,'2,5' 表示第二到第五行,$ 表示末行,'25,$' 表示第二十五行到末尾。全部输出就使用 '1,$' ,见下图, 以上就是 sed 比 grep 还要丰富的一些功能。 除此之外,sed 还有一些其他用法。 sed 的-e 选项,意思为在同一个表达式里面做多个动作,具体操作见下图, 命令 sed -e '1'p -e '/bus/'p -n test.txt ,回车之后,会先输出 '1'p 的结果,再输出 '/bus/'p 的结果。接着再通过命令 sed -e '1'p -e '/root/'p -n test.txt ,来验证结果。可以看到 root 这一行的结果输出了两遍,说明 -e 输出的是两个不同的表达式结果。三个 -e 的结果也是一样的,是互相不冲突的。 grep 里的 -i 选项可以实现不区分大小写的功能,那么 sed 里面有吗?见下图, 上图中可以看到,sed 也是区分大小写的,给 sed 加上 grep 相同的 -i 选项,没有结果输出。说明 sed 中不区分大小写的功能不是 -i 。实际上是大写的 I ,而且是加到 p 前面的。上图的结果不明显,因为第一行的结果里面有 bus 也有 Bus,来编辑一下 test.txt 文件,输入 vi test.txt ,回车,见下图, 增加上图红色框框的内容,保存后退出。接着往下操作, 可以看到,结果有匹配出来,这就是 I 的作用。 除了输出指定的行,还可以删除指定的行,具体操作见下图, 上图命令删除了文件 test.txt 的前25行,结果只显示后面的6行。接着查看文件的行数时,结果还是31行。这说明在使用 sed 删除行时,没有真正的删除行,只是在屏幕上显示出剩下的行。如果想直接删除这些行的话,可以使用 -i 选项,具体操作见下图,在删除之前,先拷贝一份, 可以看到 -i 选项,直接删除了 test.txt 文件的内容。除了删除指定的行,还可以删除指定字符串所在的行,见下图, 以上就是删除的选项 d 的作用,delete 。p 是打印输出的功能,print。

接着讲解替换功能,先将文件 test.txt 拷贝回来,见下图, 上图命令会把所有的内容都输出,然后可以看到前10行的 root 都替换成 toor 了。接着往下操作, 因为只操作了前十行,可以通过管道符用 head 来查看。结果发现,没有任何改变。这边 sed 用到 + 号的话,要加上 -r 选项才可以,见下图, 这里面要替换的字符串可以使用正则表达式,+ 、. 、(星) 、{ } 、[ ] 等等都可以识别。 接着针对前十行,来做一个操作,见下图, 以上操作的需求,是把以 : 分割的第一列和最后一列的位置替换一下,命令格式比较复杂。sed 命令是支持 | 管道符的,s 为替换符,不指定范围的话就是全部。接着对整个命令作解读: sed -r 's/([^:]+):(.):([^:]+)/\3:\2:\1/' 。第一个部分的“([^:]+):”表示第一个非 : 的字符,+ 表示一个或多个的字符,用 : 分割。中间的“(.):”,不指定特殊符号的话,会一直匹配到最后面的 : 。然后是第三个部分“([^:]+)”,表示非 : 的字符串。这边需要解释一下,上例中用 ( ) 把所想要替换的字符括起来成为一个整体,因为括号在sed中属于特殊符号,需要使用 -r 选项来脱义,用 ( ) 小括号括起来也是为了后面调用。这 ( ) 小括号里面的三部分,分别用1、2、3表示,写出来就是\1:\2:\3,这边我们是要把开头和尾部互换,所以要写成 \3:\2:\1 。 以上的思路是,本次操作的目的是要把第一段和最后一段的位置互换一下,所以就要想办法找到第一段和最后一段,因为每一行的字符串是以 : 分割的,所以可以通过 : 来作为参考对象,最后把需求表达出来。前面部分用 ( ) 小括号表示出来,后面部分就用 \ 反斜杠和数字表示。

将 root 替换成 123 ,在 sed 这边怎么表达呢?见下图, 第一个命令写了两个 // ,出现报错,说明是不对的。要解决这个问题,需要在两个 // 中间使用 \ 脱义符号。接着举例,见下图, 上图第一条命令出现报错,因为里面有好几个 \ ,系统就不知道怎么划分。有两种解决办法,一种是加上 \ 脱义符号,另一种是使用 @ 或 # 替换分隔符,只要能区分开就可以。 以上就是 sed 的查找和替换功能。

接着往下操作,将文档里的所有英文字母都删除掉,怎么表示英文字母呢?见下图, 字母表示为 [a-zA-Z] ,删除掉就是替换为空。可以看到,命令的结果只剩数字和特殊符号。

在所有行项目的前面加上字符串,具体操作见下图, 上图中,命令的需要是在所有行前面加上字符串 aaa:,(.*) 这个小括号括起来表示的是一整行,& 和 \1 的效果是一样的,表示前面的 ( ) 小括号。

总结: -e 选项,在同一个表达式里面做多个动作 -n 选项,可以只显示目标行 -r 选项,同 \ 的效果一样,表示脱义,使用了特殊符号时也需要加上 -r '2' 表示第二行,'2,5' 表示第二到第五行,$ 表示末行,'25,$' 表示第二十五行到末尾。全部输出就使用 '1,$' , I 大写的i,不区分大小写,用在 '' 单引号后面 d 删除用选项,也是用在'' 单引号后面,还有 p 输出选项 s 替换符号 g 全局替换 & 和 \1 的效果是一样的,表示前面的 ( ) 小括号 字母表示为 [a-zA-Z] ,删除掉就是替换为空