张贺,多年互联网工作经验,担任过网络工程师、系统集成工程师、LINUX系统运维工程师

笔者微信:zhanghe15069028807

1、概述

sed的作用我们就记得两条就可以了:替换和增删改查,也就是说今后当我们想对文件进行一些文字的替换和增删改查时就要想起sed

sed的语法分成三部分,我们来举一个例子:

//sed <选项-n> <对谁操作,3代表第3行> <干啥p,p代表打印>  <要操作的文件>
sed -n 3p /etc/passwd

sed的执行过程

将文件"吸入"内存,然后在内存里面处理,处理好之后将空间内的内容倾倒到屏幕。

sed常用的选项其实就三个最为常用

-n:仅显示处理的行

-r:使其支持扩展的正则表达式

-i:sed默认不改变文件的内容,使用-i会改变文件的内容,慎用!

-e:-e选项允许在同一行里执行多条命令(不好用)

2、查

1、打印整行(一或多)

1、显示文件的哪一行,或是哪几行,要求我们提示知道要显示的东西哪几一行,如果不知道想要的行在文件是第几行,那么可以先用cat -n或是less -N进行查看确认,然后再用sed打印。

//通过这个例子体会`-n`这个选项的作用
[root@zabbix3 tmp]# cat test.txt
zhanghe
zhangjia
zhangwei
[root@zabbix3 tmp]# sed 2p test.txt
zhanghe
zhangjia
zhangjia
zhangwei
[root@zabbix3 tmp]# sed -n 2p test.txt
zhangjia
[root@zabbix3 tmp]# cat test.txt
zhanghe
zhangjia
zhangwei
//仅打印最后一行
[root@zabbix3 tmp]# sed -n '2p' test.txt
zhangjia
//打印最后一行
[root@zabbix3 tmp]# sed -n '$p' test.txt
zhangwei
//下面这两个例子效果是一样的
[root@zabbix3 tmp]# sed -n '2,3p' test.txt
zhangjia
zhangwei
[root@zabbix3 tmp]# sed -n '2,+1p' test.txt
zhangjia
zhangwei

2、正则打印包含关键字的行

2、我们想要显示出现某个关键字的行,比如找出/etc/passwd当中开头是zhanghe关键字的行,我们就得使用正则表达式进行匹配,在sed当中一旦想要使用正则表达式的话就要使用//这两个符号,在这两上符号内部写正则表达式。

//其实不用sed,通过grep实现这个需求更简单,不是吗?如下所示:
[root@zabbix3 ~]# grep "^zhanghe" /etc/passwd
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash //下面是这是通过sed实现的,看着还麻烦一点
[root@zabbix3 ~]# sed -n '/^zhanghe/p' /etc/passwd
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash
// 显示结尾是/bin/bash的行
[root@zabbix3 ~]# grep '/bin/bash$' /etc/passwd
root:x:0:0:root:/root:/bin/bash
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash //下面是这是通过sed实现的
[root@zabbix3 ~]# sed -n '/\/bin\/bash$/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash

显示开头是root或者zhanghe的行

//“|”符号属于扩展的正则,所以sed加r,grep加e
[root@zabbix3 ~]# egrep '^(root|zhanghe)' /etc/passwd
root:x:0:0:root:/root:/bin/bash
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash
[root@zabbix3 ~]# sed -rn '/^(root|zhanghe)/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash

打印出开头是root行一直到结尾nologin的中间的行,我们还是可以使用正则表达式

[root@localhost ~]# sed -n '/^root/,/nologin$/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

其实用正则表达式匹配范围非常适合我们用来查看日志,假如说我们查看一下某个时间点到另一个时间点之间发生了什么事情?如下所示:

[root@localhost ~]# sed -n '/Oct 21 15:42:48/,/Oct 21 16:09:26/p' /var/log/secure

2、增

增常常于查连用,而查无非是根据行号和正则表达式查询,一定要体会到这个联系!才会把sed的查和增联系起来

我们在文本后面增加东西有几种方法呢?vim、nano、>>(echo 、cat)除了这些方法之后,在文本里面增加内容也只有sed了。

通过sed在文本里面增加内容实际上非常的简单,主要就用到三个选项:a/i/c。

a:apped在匹配到的行下面加

i:insert在匹配到的行上面加

r:在行的后面加内容,加的内容必须来自于文件

c:把这一行内容替换成你想要的内容 #看着是不是有点熟悉,grep也有类似的选项

y:作用字符替换,将匹配的内容做替换

w:将匹配到的行输出到另一个文件

//在文本的第3行下面添加两行内容
[root@localhost ~]# sed '3azhanghe\nzhanghe' /etc/passwd zhanghe,zhanghe //在开头是root的行下面添加两行内容zhanghe,zhanghe
[root@localhost ~]# sed '/^root/azhanghe\nzhanghe' /etc/passwd //把第一行整体替换成zhanghe,这是替换的一整行
[root@localhost ~]# sed '1czhanghe' /etc/passwd | head -2
zhanghe
bin:x:1:1:bin:/bin:/sbin/nologin //在/etc/passwd文件里面匹配到以root开头的行,然后这一行的下一行添加/tmp/text.txt里面的内容
sed '/^root/r /tmp/text.txt' /etc/passwd //把text.txt文件里面包括my的行放置到text2.txt里面,注意这里面的顺序
sed -n '/my/w test2.txt' test.txt 将前10行当中的所有小写的s转换成大写的S和将全文所有小写的s转成大写的S
sed '1,10y/s/S/' /etc/passwd

3、删

删除最简单的了,就是使用一个局部命令d就可以了,如下所示:

//删除第一行
sed '1d' /tmp/passwd //删除1、2、3行
sed '1,3d' /etc/passwd //删除开头的root的行一直到结尾是nologin的行
sed '/^root/,/nologin$/d' /tmp/passwd
//删除开头是#号的行
sed '/^#/d' /etc/nginx/nginx.conf //删除真空行
sed '/^$/d' /etc/nginx/nginx.conf //删除带空格的假空行(平时记住这个即可)
sed '/^[[:space:]]*$/d' /etc/nginx/nginx.conf

4、替换

在sed的替换功能这里面我们要对替换做一个总结,文本的替换有很多方法,我们来总结一下,当前讲的sed的通用替换方式即:s@@@这种方式, 这种方式是通用的查找到什么就能替换什么,灵活强大,某字符的替换、大小写的替换皆可做,但是整行的替换通过s@@@不太好做,需要用到二级命令c

//字符替换(词语、单个字符)
sed 's@root@R00T@g' /etc/passwd
sed '1,10y/s/S/' /etc/passwd
tr 's' 'S' < /etc/passwd //大小写的转换,u和l代表和upper和lower
sed 's@[a-z]@\u&@g' file
sed 's@[A-Z]@\l&@g' file
tr '[a-z]' '[A-Z]' < /etc/passwd
tr '[[:lower:]]' '[[:upper:]]' < /etc/passwd //整行替换,将第二行无论什么内容都替换成888
sed 2c888 /etc/passwd

替换是sed最重要的功能,也比较简单,我们只需要记住sed替换的标准格式,即:

//s是`sub`的意思,g是`global`就是全局的意思,整体意思就是全局替换。
sed 's@@@g'
[root@localhost tmp]# cat test.txt
zhanghe
zhangmin
zhangjia
zhanghe
zhanghezhanghe // 不加g,只会替换第一行
[root@localhost tmp]# sed 's@zhanghe@hello@' test.txt
hello
zhangmin
zhangjia
hello
hellozhanghe //加上g就是全局替换
[root@localhost tmp]# sed 's@zhanghe@hello@g' test.txt
hello
zhangmin
zhangjia
hello
hellohello

其实g所在的位置指代的是哪几代,g是指全部嘛,如果写一个3那就是第三列,也就是说我们可以指定替换哪一列当中的字符串,如下所示,我们替换第三列当中的zhanghehello

[root@localhost tmp]# cat test.txt
zhanghe
zhangmin
zhangjia
zhanghe
zhanghezhanghe
zhanghe //#只有第三列变化了,第一列和第二列的zhanghe都没有被替换
[root@localhost tmp]# sed 's@zhanghe@hello@3' test.txt
zhanghe
zhangmin
zhangjia
zhanghe
zhanghezhanghe hello #注意,这是按照词语进行替换的,我们上面讲的-c选项是按行进行替换的。

在替换当中,只有第一个条件可以使用模式,第二个不可以

[root@zhanghe ~]# cat zh.txt
i like
on,my,love
[root@zhanghe ~]# sed 's#\(l..e\)#\1r#' zh.txt #把l..e替换成l..er
i liker
on,my,lover
[root@zhanghe ~]# sed 's#l\(..e\)#L\1#' zh.txt #仅把l..e的l替换成大写
i Like
on,my,Love
//利用sed命令把history开始的空白字符给删除了
history | sed 's@^[[:space:]]*@@'
history | sed 's@^[[:space:]]\+@@g'
history|sed 's#^[[:space:]]\{3\}##g'

5、后向引用

所谓的后向引用就是将想要引用的东西用括号包起来,如果再用到的话就可以直接调用了,就是这么简单。

[root@localhost tmp]# echo 123456 | sed -r 's@(.*)@\1@g'    #.*就代表所有
123456
[root@localhost tmp]# echo 123456 | sed -r 's@1234(.*)@\1@g' #这个所有指代的就是5和6
56
//取IP
[root@zabbix3 ~]# ifconfig eth0 | sed -n 2p
inet 192.168.80.199 netmask 255.255.255.0 broadcast 192.168.80.255
[root@zabbix3 ~]# ifconfig eth0 | sed -n 2p | sed -r 's@^.*et (.*) net.*@\1@'
192.168.80.199

6、结合

同时执行多条sed语句,-e选项允许在同一行里执行多条命令

//先将第2行到最后一行给删除了,只留下第一行,然后将第一行的ROOT替换成TTTTT
sed -e '2,$d' -e 's@ROOT@TTTTT@' /etc/passwd

7、练习

删除/etc/grub.conf文件中行首的空白字符(提示:替换)

[root@zhanghe ~]# sed 's@^[[:space:]]@@' /etc/grub.conf

替换/etc/inittab文件当中的id:3:initdefault:一行当中的数字为5(提示:后向引用)

[root@A ~]# sed "s%^id:[0-9]:initdefault:$%id:5:initdefault:%" /etc/inittab
[root@China ~]# sed "s@\(id:\)[0-9]\(:initdefault:\)@\15\2@g" /etc/inittab
sed "s@\(id:\)[[:digit:]]\(:initdefault:\)@\16\2@" /etc/inittab
sed -r -i "s@(id:)[[:digit:]](:initdefault:)@\16\2@" /etc/inittab

删除/etc/inittab文件当中的空白行(提示:删除)

[root@China ~]# sed "/^[[:space:]]*$/d" /tmp/grub.conf

删除/etc/inittab文件当中以#开头的行(提示:删除)

[root@zhanghe ~]# sed  "/^#/d" /etc/inittab

删除某文件中开头的#及后面的空白字符的行,但要求#号后面必须有空白字符(提示:删除)

[root@zhanghe ~]# sed "/^#[[:space:]]/d" test.sh

删除某文件中以空白字符后面跟#号的行中开头的空白字符及#(提示:删除)

[root@zhanghe ~]# sed "s@^[[:space:]]\+#@@" test.sh

取出一个文件路径的目录名称(后向引用)

[root@China ~]# echo "/etc/sysconfig" | sed 's@[^/]\+$@@'
/etc/
[root@China ~]# echo "/etc/sysconfig/" | sed 's@[^/]\+$@@'
/etc/sysconfig/
[root@China ~]# echo "/etc/rc.d" | sed -r "s@^(/.*/)[^/]+/?@\1@g"
/etc/
[root@China ~]# echo "/etc/rc.d" | sed -r "s@[^/]+/?\$@@g"
/etc/

解析:第一回是在线开头的字符至少出现一次,并且还要在词尾给删了,删除之后可不就剩下斜线开头的目录了嘛,但是,如果目录是一个绝对路径呢?就像

echo /zhang/he/ | sed "s@\(\/[[:alnum:]]\+\/\)\([[:alnum:]]\+\/\?\)@\1@"
/zhang/
echo /zhang/he/ | sed "s@\(\/[[:alnum:]]\+\/\)\([[:alnum:]]\+\/\?\)@\2@"
he/

取出一个目录的基名和目录名()

[root@China ~]# basename /etc/sysconfig
sysconfig
[root@China ~]# dirname /etc/sysconfig
/etc

把/etc/fstab当中空行和开头是空格的、开头是#号都删除掉(提示:删除)

//把/etc/fstab当中空行和开头是空格的、开头是#号都删除掉
sed 's@^#@@' /etc/fstab | sed '/^[[:space:]]*$/d' | sed 's@^[[:space:]]@@' //把/etc/fstab当中空行和开头是空格的、开头是#号的行都删除掉,注意,上面是删除字,实质是替换,这里是删行
sed '/^#/d' test.txt | sed '/^[[:space:]]/d' | sed '/^[[:space:]]*$/d'

打印奇数或偶数行

sed -n 'p;n' <file>   #打印奇数行
sed -n 'n;p' <file> #打印偶数行

打印完前三行后,退出sed

[root@zhanghe ~]# sed '3q' /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

将文件当中所有的字母转成大写

最好的办法不是使用sed而是使用tr,如果tr命令的话是这样:

tr 'a-z' 'A-Z' < file

将文件当中前10的abcde转成为大写

sed '1,10y/abcde/ABCDE/' /etc/passwd

将前10行当中的所有小写的s转换成大写的S和将全文所有小写的s转成大写的S

sed '1,10y/s/S/' /etc/passwd
sed 's@s@S@g' /etc/passwd

8、进阶

是否真正理解了sed是一个编辑器?

sed是一个行编辑器,行编辑器的意思是只能一行行的处理,比如你可以删除任意行,但不能删除某一行当中的某一个字段,如下所示:

//删除第二行
[root@n9 ~]# cat -n /etc/issue
1 \S
2 Kernel \r on an \m
3 [root@n9 ~]# cat -n /etc/issue | sed 2d
1 \S
3 //删除第二行当中on单词,是无法删除的,无法删除的原因并不是没有匹配上,而是做不到,
[root@n9 ~]# cat -n /etc/issue | sed -n 2p | sed '/on/d'
2 Kernel \r on an \m //通过grep我们可以确定最后一个sed是一定是匹配到了on,但sed删除功能的细粒度只是行而已,做不到仅删除字符串。

在使用替换s@A@B@格式的时候,第一次匹配,也就是A处的匹配一定要把一整行全都匹配上,不能仅仅匹配一行当中的某个或某些字段,这么说有些抽象,我们用例子来说明:

[root@n9 ~]# ifconfig eth0 | sed -n 2p
inet 192.168.80.59 netmask 255.255.255.0 broadcast 192.168.80.255
[root@n9 ~]# ifconfig eth0 | sed -n 2p | sed -r 's@^.*inet (.*) netmask@\1@'
192.168.80.59 255.255.255.0 broadcast 192.168.80.255
[root@n9 ~]# ifconfig eth0 | sed -n 2p | sed -r 's@^.*inet (.*) netmask.*@\1@'
192.168.80.59
[root@n9 ~]# ifconfig eth0 | sed -n 2p | sed -r 's@^.*inet (.*) netmask@\1@'
192.168.80.59 255.255.255.0 broadcast 192.168.80.255

上面这个为什么会出错呢?不是因为扩展的正则表达式写错了,那我怎么肯定我没有写错呢?通过egrep就可以确定,我把sed使用的扩展正则表达式^.*inet (.*) netmask放到egrep里面,就能看见到底匹配到了哪些内容,如下所示,内容并没有匹配错:

[root@n9 ~]# ifconfig eth0 | egrep -o '^.*inet (.*) netmask'
inet 192.168.80.59 netmask
//这条命令到底错了哪里?
[root@n9 ~]# ifconfig eth0 | sed -n 2p | sed -r 's@^.*inet (.*) netmask@\1@'
192.168.80.59 255.255.255.0 broadcast 192.168.80.255

如上所示,在s@^.*inet (.*) netmask@\1@正则表达式当中,(.*)匹配的内容并不仅仅匹配的是inet后面的内容和netmask前面的内容,(.*)的真正的含义是匹配除了^.*inet匹配到的,和除了netmask这个单词之外内容,结果就是就把192.168.80.59 255.255.255.0 broadcast 192.168.80.255给匹配出来了。

解决办法我们上面说过了,只要在第一次匹配的时候把要处理的行匹配完整,就不会有这种情况发生,也就是在netmask后面加上.*,这样就把一行匹配完整了,下面举几个例子:

[root@n9 ~]# ifconfig eth0 | sed -n 2p | sed -r 's@^.*inet (.*) netmask.*@\1@'
192.168.80.59
ip addr show eth0 | sed -n 3p
inet 192.168.80.59/24 brd 192.168.80.255 scope global noprefixroute eth0 ip addr show eth0 | sed -n 3p | sed -r 's@[[:space:]]+inet (.*) brd@\1@'
192.168.80.59/24 192.168.80.255 scope global noprefixroute eth0 ip addr show eth0 | sed -n 3p | sed -r 's@[[:space:]]+inet (.*) brd.*@\1@'
192.168.80.59/24 ip addr show eth0 | sed -n 3p | sed -r 's@[[:space:]]+inet (.*) (\bbrd\b.*eth0$)@\1@'
192.168.80.59/24

sed命令总结的更多相关文章

  1. 文本处理三剑客之sed命令

    第十八章.文本处理三剑客之sed命令 目录 sed介绍 sed命令常用选项 sed常用编辑命令 sed使用示例 sed高级语法 18.1.sed简介 sed全名stream editor,流编辑器,s ...

  2. linux shell 用sed命令在文本的行尾或行首添加字符

    转自 http://www.cnblogs.com/aaronwxb/archive/2011/08/19/2145364.html 昨天写一个脚本花了一天的2/3的时间,而且大部分时间都耗在了sed ...

  3. linux sed命令详解

    简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...

  4. sed命令详解

    搜索 纠正错误  添加实例 sed 功能强大的流式文本编辑器 补充说明 sed 是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时 ...

  5. Linux安全基础:sed命令的使用

    sed 是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作. Sed本质上是一个编辑器,但是它是非交互式的,这点与VIM不同:同时 ...

  6. [转]sed命令详解

    转载:http://blog.chinaunix.net/u/22677/showart_1076318.html   1.简介 sed是非交互式的编辑器.它不会修改文件,除非使用shell重定向来保 ...

  7. sed命令

    sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法sed命令行格式为:         sed ...

  8. sed 命令使用

    ios 的sed 命令 跟linux  sed 命令有区别 # 所有的a 替换成b sed -i "" 's/a/b/g' #删除掉所有包含a的行 sed -i "/a/ ...

  9. sed命令给文本文件的每行的行首或者行尾添加文字

    在每行的头添加字符,比如"HEAD",命令如下: sed 's/^/HEAD&/g' test.file 在每行的行尾添加字符,比如“TAIL”,命令如下: sed 's/ ...

  10. Linux的sed命令

    一.初识sed 在部署openstack的过程中,会接触到大量的sed命令,比如 # Bind MySQL service to all network interfaces.sed -i 's/12 ...

随机推荐

  1. 技术分享预告丨k3s在边缘计算中的应用实践

    技术分享是在[Rancher官方微信技术交流群]里以图文直播+QA实时互动的方式,邀请国内已落地经验的公司或团队负责人分享生产落地的最佳实践.记得添加微信小助手(微信号:rancher2)入群,实时参 ...

  2. 【原创】WinForm中实现单独Time控件的方式

    WinForm默认只提供了DateTimePicker,今天的项目只用时间,不能出现日期,百撕不得骑姐(^^),也没花多少时间,随便试了一下,就成功了,分享一下. 在DateTimePicker属性中 ...

  3. AssemblyBuilder以及Activator双剑合璧

    AssemblyBuilder和Activator两个类是DispatchProxy类实现动态代理以及AOP的根本,示例demo可参考 DispatchProxy实现动态代理及AOP .Assembl ...

  4. Flutter学习笔记(22)--单个子元素的布局Widget(Container、Padding、Center、Align、FittedBox、Offstage、LimitedBox、OverflowBox、SizedBox)

    如需转载,请注明出处:Flutter学习笔记(22)--单个子元素的布局Widget(Container.Padding.Center.Align.FittedBox.Offstage.Limited ...

  5. canvas绘制线条详解

    canvas详解----绘制线条 <!DOCTYPE html> <html> <head> <title>canvas详解</title> ...

  6. com.mysql.cj.exceptions.DataReadException: Zero date value prohibited

    com.mysql.cj.exceptions.DataReadException: Zero date value prohibited at com.mysql.cj.result.SqlTime ...

  7. 关于jQuery MiniUI

    jQuery MiniUI v3.0 jQuery MiniUI - 专业WebUI控件库.它能缩短开发时间,减少代码量,使开发者更专注于业务和服务端,轻松实现界面开发,带来绝佳的用户体验. http ...

  8. springboot 多环境

    springboot 多环境 --spring.profiles.active=dev 查看 Ioc 容器 PostProcessorRegistrationDelegate

  9. Unable to open debugger port: java.net.SocketException

    网上都说是tomcat端口被占用,其实不是,这是因为文件权限不够,脚本不能执行,debug当然不能接受网络连接的数据 可以在Event Log里看到 所以只需要更改文件的级别就可以了(可读可写可执行) ...

  10. 上手OrangePi Zero+

    一.安装系统 所需材料:系统镜像文件.镜像烧录工具.至少2G的内存卡(推荐8G以上).读卡器 1.下载系统镜像 官方系统下载地址,由于官方系统更新截止到17年,所以我选择的是Armbian系统.下载地 ...