张贺,多年互联网工作经验,担任过网络工程师、系统集成工程师、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. Java开发中解决Js的跨域问题

    主流方法有JSONP和CORS两种,这里记一下后者的方式,理论基础就是在请求的时候在http请求头中添加如下属性: //指定允许其他域名访问 Access-Control-Allow-Origin:h ...

  2. Spring Security OAuth2 开发指南(非最新版本)

    请注意哈,本文翻译的时候,官网的的版本和本文翻译的时候是一一对应的. 但是官网已经更新文档和概念了,因此和本文翻译的就不在是同一个范围了. 因此我已经将标题修改为(非最新版本),各位老铁直接看官网就可 ...

  3. PlayJava Day027

    进程状态 1.创建状态:在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态 此时,它已经有了相应的内存空间和其他资源,但还处于不可运行状态 新建一个线程对象可采用Thread类的构造方 ...

  4. CSS之border绘制三角形

    用CSS的border可以画出高质量的三角形. 我们一般会这么使用border: #test-border { width: 100px; height: 100px; margin: 100px a ...

  5. FCC---CSS Flexbox: Apply the flex-direction Property to Create Rows in the Tweet Embed

    The header and footer in the tweet embed example have child items that could be arranged as rows usi ...

  6. Android项目实战之高仿网易云音乐项目介绍

    这一节我们来讲解这个项目所用到的一些技术,以及一些实现的效果图,让大家对该项目有一个整体的认识,推荐大家收藏该文章,因为我们发布文章后会在该文章里面加入链接,这样大家找着就很方便. 目录 第1章 前期 ...

  7. [Go] 轻量服务器框架基础TCP连接的抽象和封装

    对tcp连接部分以及与连接绑定的业务部分进行抽象和封装 主要是对连接的开启关闭和读写进行封装,抽象出接口,使用回调进行具体业务的绑定 zinterface/iconnection.go package ...

  8. [Go] golang中的包管理

    在配置了环境变量$GOPATH后,比如下面这个路径 export GOPATH=/mnt/f/ubuntu/goProject 在这个路径下面会有这几个目录 在src目录下放着我的源码比如: 在同一个 ...

  9. 20182320《Program Design and Data Structures》Learning Summary Week9

    20182320<Program Design and Data Structures>Learning Summary Week9 1.Summary of Textbook's Con ...

  10. Win10 中 Git clone github上内容保存到指定文件夹

    在要存储的右键→Git Bash Here 弹出命令窗口 输入 git clone 链接 很快就下载完成