查看原文
其他

正则表达式(5)-三剑客之sed

Cloud研习社 Cloud研习社 2023-06-06


每周二、四、六定期更新!


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代表打印出替换的行。


我们来几个企业情境应用实战的练习:
企业实战1:去掉ifconfig的结果的第二行行首并打印出来第二行


[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选项。


企业实战3:给/etc/fstab 中没有加注释的行加上注释,即为不是“#”号开头的行加上“#”号
# 思路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参数


课后实践及总结:
  1. 企业实战题:有一个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"}


  1. 企业实战题:请把/etc/fstab中所有以“#”开头的行中的“#”去掉。(要求:请把/etc/fstab复制到一个练习用的目录中,为sed加上-i选项修改文件)

  2. 企业实战题:取出这个”/usr/lib/systemd/system/“路径中的最后”system“这个名字(即取出最后一级的文件名或目录名)

  3. 企业实战题:使用sed取出ifconfig ens33命令获得的IP地址

  4. 请总结:

  • 获取IP地址的几种方法的思路及实现方式

  • 总结sed的基本使用方法


手应知:

    尝鲜Rocky Linux

《Linux基础及进阶》:

    059 - Shell基础(11)-关于shell语句中小括号()和大括号{}的作用    060 - 正则表达式(1)-基本正则表达式1    061 - 正则表达式(2)-基本正则表达式2    062 - 正则表达式(3)-扩展正则表达式    063 - 正则表达式(4)-三剑客之grep


看完本文有收获?请分享给更多人


推荐关注「Cloud研习社」,带你从零开始掌握云计算技术!

微信号|bjdream-1


Cloud研习社 · 

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存