正则表达式(5)-三剑客之sed
每周二、四、六定期更新!
sed基本应用
Sed (stream editor)主要用来自动编辑一个或多个文件、简化对文件的反复操作。
sed是按照行处理文本,读取一行处理一行,并将输出结果发送到屏幕。完成后再读取下一行并处理,直至全部处理完成。sed把当前正在处理的行保存在一个临时缓冲区中,这个缓存区称为模式空间,sed处理完模式空间中的行后,就把行打印到屏幕上。sed处理行会把行放在模式空间中,不会改变原文件。sed对文件的处理过程见下图:
sed [option] 'sed_script' inputfile
常用选项:
-n 仅显示sed_script处理后的结果,即关闭sed默认的打印
-e 多点编辑,以选项中指定的script来处理输入的文本文件。
-i.bak 先备份文件,再对文件处理,文件内容会被修改。
-r 支持使用正则表达式
sed_script格式:‘地址 命令’
地址格式:
不写地址:对全文进行处理 单地址:
#:"#"是一个数字,表示显示指定的行
$:代表最后一行
/pattern/: 能够被pattern匹配到的所有行
地址范围
#,#: "#"是一个数字,表示从第几行到第几行
#,+#: 例如2,,+7,表示从第2行以及其后的7行
/pat1/,/pat2/: 从pat1匹配的行到pat2匹配的行及其中间的所有内容
#,/pat1/: 从第几行到pat1匹配的中间的所有行
步进:~
示例:
1~2 表示从1开始,每隔一行打印
命令格式:
p 打印符合条件的行
d 删除匹配的行,默认只是在显示效果中把匹配到的行删掉,并不会真正从文件中删除行。
a 【\】text在匹配行的后面追加内容。【】内的“\”可以省略
i 【\】text 在匹配行的前面插入内容。【】内的“\”可以省略
c 【\】text 替换匹配的行。【】内的“\”可以省略
w 把匹配到的内容写入到一个文件中(和重定向的效果一样)
r 从某个文件读入内容
! 取反。过滤出不符合条件的内容
查找替换
s/pattern/string/ 修饰符查找替换,“/”可以换成@或者# 【这部分的使用和vim中的查找替换使用方式基本一致】
修饰符:
g:行内全局替换
p:显示替换成功的行
w /path/file:把替换成功的行写入file文件
实例讲解:
# 实例1:
[root@studyclub jason]# sed '' passwd # 效果相当于cat。读取passwd的每一行,但是不做处理,sed默认会显示,所以能看到文件
[root@studyclub jason]# sed 'p' passwd # 这个命令会把每一行都打印两次。读取passwd的每一行,用p命令打印出来,同时sed会自动打印,这样就会出现每一行打印两次的效果。
# 实例2:-n,关闭自动打印。(可以和实例1对比一下,看看实际效果的差别)
[root@studyclub jason]# sed -n '' passwd
[root@studyclub jason]# sed -n 'p' passwd
# 实例3:显示指定的行(显示第几行、显示最后一行)
[root@studyclub jason]# sed -n '1p' passwd # 显示第一个行
[root@studyclub jason]# sed -n '1,4p' passwd # 显示第1到4行
[root@studyclub jason]# sed -n '$p' passwd # 显示最后一行(相当于tail -n1 passwd)
# 实例4:sed支持标准输入
[root@studyclub jason]# ifconfig | sed -n '2p' # 显示ifconfig结果的第二行。
# 实例5:正则表达式。查找硬盘设备文件
[root@studyclub jason]# df | sed -n '/\/dev\/sd/p'
# 实例6:显示从某个字符串到某个字符串之间的内容。比如:查看某个特定时间段内的日志:
[root@studyclub jason]# sed -n '/2021-5-01/,/2021-5-20/p' access_log # 查看从5月1号到5月20号的所有日志
# 实例7:每个3行打印内容
[root@studyclub jason]# seq 10 | sed -n '1~3p' # 从第一行开始,每隔2行打印
1
4
7
10
[root@studyclub jason]# seq 10 | sed -n '3~4p' # 从第三行开始,每隔3行打印
3
7
# 实例8:删除特定的行
[root@studyclub jason]# seq 10 | sed '3~4d'
# 实例9:
[root@studyclub jason]# seq 20 > seq.log # 创建需要使用的文件
[root@studyclub jason]# sed -i.bak '2,19d' seq.log # 删除第2-19行,删除之前先备份
[root@studyclub jason]# ls seq.log # 查看是不是有备份文件
seq.log seq.log.bak
[root@studyclub jason]# cat seq.log # 查看文件内容是不是被修改了
1
20
# 实例10:多点编辑
[root@studyclub jason]# sed -e '2,4d' -e '10,19d' seq.log # 通过-e指定两个动作,这就是多点编辑
# 实例11:追加内容。(在行前插入内容,即i的用法请自行练习)
[root@studyclub jason]# sed '1~2ajason' seq.log # 本例:在奇数行后面后面追加内容“jason”。1~2a表示在奇数行后追加内容,jason就是要追加的内容
[root@studyclub jason]# sed '/^1/ajames' seq.log # 在1开头的行后面追加james字符串
# 给httpd.conf配置文件添加一个新的监听端口8080
[root@studyclub jason]# sed '/^Listen 80/a Listen 8080' /etc/httpd/conf/httpd.conf
# 实例12:替换匹配的内容
[root@studyclub jason]# sed '/^1/cjames' seq.log # 以1开头的行全部替换成james
# 把httpd.conf配置文件监听的80端口替换成443
[root@studyclub jason]# sed '/^Listen 80/c Listen 443' /etc/httpd/conf/httpd.conf
[root@studyclub jason]# sed '/^Listen 443/a Listen 80 \n\ Listen 8081' /etc/httpd/conf/httpd.conf # 添加两行,\n后面的“\”代表分界符,这样我们后面写上的空格也作为一部分内容添加到文件中,这里效果就是Listen 8081不在行的开头,该行的开头是连续的几个空格。
# 实例13:查看不符合条件的内容
[root@studyclub jason]# sed -n '/^#/!p' /etc/fstab # 打印不以“#”开头的行
# 实例14:查找passwd文件中的root并替换成studyclub。
[root@studyclub jason]# sed 's/root/studyclub/' passwd # 这样我们可以发现只替换了查找到的第一个root,如果希望查找到的所有root都被替换,可以加上“g”这个修饰符,如下
[root@studyclub jason]# sed 's/root/studyclub/g' passwd
# 如果我们还希望能够把替换的行打印出来,可以加上“p”修饰符:
[root@studyclub jason]# sed -n 's/root/studyclub/gp' passwd
# 实例15:sed中使用扩展的正则表达式,配合分组、后向引用进行练习
[root@studyclub jason]# sed -rn 's/(r..t)/\1ER/gp' passwd # 把r..t替换成r..tER
# 解析:加上-r是为了让sed支持扩展的正则表达式,()表示分组,\1是反向引用,代表前面括号里的r..t匹配的内容。后面的g代表全部替换,p代表打印出替换的行。
[root@studyclub jason]# ifconfig ens33 | sed -n '2s/^.*inet //gp'
10.0.0.136 netmask 255.255.255.0 broadcast 10.0.0.255 # 怎么样,行首去掉了吧,直接以IP地址开头了。
# 在上一步的基础上我们继续处理,进而拿到ip地址
[root@studyclub jason]# ifconfig ens33 | sed -n '2s/^.*inet //gp' | sed -n 's/netmask .*//gp'
10.0.0.136
# 我们再简化一下命令:
[root@studyclub jason]# ifconfig ens33 | sed -n '2s/^.*inet //;s/netmask.*//p'
10.0.0.136
# 我们用分组的方式,把需要的ip地址留下。我们先来看ifconfig ens33的结果:
[root@studyclub jason]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.136 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::b346:6acb:2872:19c6 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:75:96:58 txqueuelen 1000 (Ethernet)
RX packets 76082 bytes 23755246 (22.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 41975 bytes 8471638 (8.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 第二行中我们可以把inet及以前的内容作为第一个分组,10.0.0.136作为第二个分组,netmask及以后的内容作为第三个分组,然后我们用第二个分组替换就可以了。
[root@studyclub jason]# ifconfig ens33 | sed -nr '2s/(.*inet )([0-9].*)( netmask.*)/\2/gp'
10.0.0.136
企业实战2:修改网卡名称。centos6里,网卡都是eth0,1,2...这种命名方式,但是centos7里我们看到是ens33,34...这种命名方式,我们现在把它改成centos6里的命名方式,需要我们在/etc/default/grub里修改GRUB_CMDLINE_LINUX字段,添加net.ifnames=0 biosdevname=0即可。
# 思路1:找到“GRUB_CMDLINE_LINUX=”开头的行,然后用正则表达式匹配到最后一个引号,最后一个引号前面的内容作为一个整体(不包括最后一个引号),然后在整体的后面接上“net.ifnames=0 biosdevname=0”即可。
[root@studyclub ~]# sed -nr '/^GRUB_CMDLINE_LINUX=/s/(.*)"$/\1 net.ifnames=0 biosdevname=0"/p' /etc/default/grub
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet net.ifnames=0 biosdevname=0"
# 思路2:把行尾的引号替换成net.ifnames=0 biosdevname=0"即可。
[root@studyclub ~]# sed -nr '/^GRUB_CMDLINE_LINUX=/s/"$/ net.ifnames=0 biosdevname=0"/p' /etc/default/grub
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet net.ifnames=0 biosdevname=0"
# 当然,仅修改这个文件还是不能完成修改网卡名称的工作,这只是修改网卡名称中的其中一步。这里我们仅仅是为了练习sed的用法,所以我们sed没有添加-i选项。
# 思路1:先找到不是以“#”号开头的行,然后每行的开头用“#”代替
[root@studyclub jason]# sed -nr '/^#/!s/^/#/gp' /etc/fstab # 注意:我们并没有修改文件,如果想要修改文件,请为sed加上-i参数
# 思路2:把不是以“#”开头的行的前面加上“#”号
[root@studyclub jason]# sed -nr 's/^[^#](.*)/#\1/pg' /etc/fstab # 注意:我们并没有修改文件,如果想要修改文件,请为sed加上-i参数
企业实战题:有一个info.json文件,内容如下:
{"message_type":"MNLG","message_time":"2021-07-13 09:51:35","hardware_code":"KTP7G4J7-RMPVJ7T3-VTQXC4D9-C6FVWWP6","log_type":1,"gentime":"2021-07-13 09:51:35","username":"studyclub","status":1,"action":"\u7528\u6237\u767b\u5f55","object":"studyclub","detail":null,"userip":"10.201.78.5"}
请把action部分去掉,变成如下的样子:
{"message_type":"MNLG","message_time":"2021-07-13 09:51:35","hardware_code":"KTP7G4J7-RMPVJ7T3-VTQXC4D9-C6FVWWP6","log_type":1,"gentime":"2021-07-13 09:51:35","username":"studyclub","status":1,"object":"studyclub","detail":null,"userip":"10.201.78.5"}
企业实战题:请把/etc/fstab中所有以“#”开头的行中的“#”去掉。(要求:请把/etc/fstab复制到一个练习用的目录中,为sed加上-i选项修改文件)
企业实战题:取出这个”/usr/lib/systemd/system/“路径中的最后”system“这个名字(即取出最后一级的文件名或目录名)
企业实战题:使用sed取出ifconfig ens33命令获得的IP地址
请总结:
获取IP地址的几种方法的思路及实现方式
总结sed的基本使用方法
《Linux基础及进阶》:
059 - Shell基础(11)-关于shell语句中小括号()和大括号{}的作用 060 - 正则表达式(1)-基本正则表达式1 061 - 正则表达式(2)-基本正则表达式2 062 - 正则表达式(3)-扩展正则表达式 063 - 正则表达式(4)-三剑客之grep看完本文有收获?请分享给更多人
推荐关注「Cloud研习社」,带你从零开始掌握云计算技术!
微信号|bjdream-1
Cloud研习社 ·