4.1 工作原理
sed 即 Stream EDitor,和 vi 不同,sed是行编辑器
- Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行
- 每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间pattern space
- 一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象
=
4.2 命令选项⭐
sed [option]... 'script ; script ;...' file...
其中 "script" = 地址&动作
多个script表示 可以同时进行多个script操作,用 ; 隔开(如'2p;5p')
-n 不输出模式空间内容到屏幕,即不自动打印(核心选项)
-e 多点编辑!!!适合用于编辑配置文件
-r/E 使用扩展正则表达式(扩展)
-i 直接编辑不备份
-i.bak '先备份文件并编辑源文件'
-f /PATH/SCRIPT_FILE 从指定文件中读取编辑脚本
=
4.2.1 script 地址锚定
- 可组合使用,自定义指定想要的行
- 指定具体行号不需要斜线!!!
1.不给地址:对全文进行处理
=======================
2.单地址:
#: 指定的行
$: 最后一行
/pattern/: 能被此模式匹配到的每一行(正则)
=========================================
3.范围地址:
#, # 第几行到第几行
#,+# 从第几行到后续几行
/pat1/,/pat2/ 从 【pat1匹配到的行】 到 【pat2匹配到的行】
#,/pat/ 从 【第#行】 到 【pat匹配到的行】
=======================================================
4. 步进:~
1~2 奇数行
2~2 偶数行
=
4.2.2 script 处理命令
- 只能单独使用!即一次只能进行一种处理动作
- 特殊情况:不输入命令,表示只匹配行,不进行其他操作
# 常用:
p 打印当前模式空间内容,追加到默认输出之后
d 删除模式空间匹配的行,并立即启用下一轮循环(取反)
# 注意:以下[\]是可选占位符。。。若不写,此处也要留出空格
a\text 在指定行下一行插入文本行,'支持使用\n实现多行追加
i\text 在指定行上一行插入文本行
c\text '替换指定行内容'为单行或多行文本
===================================================
# 不常用:
w /path/file 保存模式匹配的行至指定文件
r /path/file 读取指定文件的文本至模式空间中匹配到的行后
= 只显示匹配到的'行号'
! 模式空间中匹配行取反处理
==================================================
# 说明:整个 s/// 是一个script命令! 前面还可以加上地址限定条件:'/pat/s/pat/string/修饰符'
s/pattern/string/修饰符
查找替换,支持使用其它分隔符:s@@@,s###
# 修饰符:
g 行内全局替换(一行之内可能有多处符合要求)
p 显示替换成功的行 '核心动作'
w /PATH/FILE 将替换成功的行保存至文件中
=
=
4.2.3 范例汇总
1范例:可接受标准输入
[root@centos8 ~]# sed '' 表示script内容为空
ddd
ddd
dddddddd
dddddddd
fffffffffffffffffff
fffffffffffffffffff # 使用ctrl+D退出
[root@centos8 ~]#
=
1 原理演示⭐
2范例:模式空间输出原理
# sed 默认相当于echo一次,'p'再次打印,-n不打印
[root@centos8 ~]# sed '' /etc/issue # 正常输出原文
\S
Kernel \r on an \m
#---------------
[root@centos8 ~]# sed -n '' /etc/issue # 不输出内容
[root@centos8 ~]# sed 'p' /etc/issue # 每行重复
\S
\S
Kernel \r on an \m
Kernel \r on an \m
#---------------
[root@centos8 ~]# sed -n 'p' /etc/issue # 加一减一还是正常输出原文
\S
Kernel \r on an \m
[root@centos8 ~]#
=
2 指定行
3范例:输出指定的【某一行】
[root@centos8 ~]# sed -n '1p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos8 ~]# sed -n '2p' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
[root@centos8 ~]# sed -n '3p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@centos8 ~]# ip a | sed -n '9p'
inet 10.0.0.8/24 brd 10.0.0.255 scope global noprefixroute ens160
=
4范例:输出指定的【连续几行】
[root@centos8 ~]# seq 9 | sed -n '2,5p'
2
3
4
5
[root@centos8 ~]# seq 9 | sed -n '2,+2p'
2
3
4
[root@centos8 ~]# seq 9 | sed -n '7,$p'
7
8
9
=
5范例:取奇数或偶数行
[root@centos8 ~]# seq 8 | sed -n '1~2p'
1
3
5
7
[root@centos8 ~]# seq 8 | sed -n '2~2p'
2
4
6
8
# 使用命令 d 表示删除匹配到的行,效果是取反!!!(不能再加选项 -n)
[root@centos8 ~]# seq 6 | sed -n '1~2d'
[root@centos8 ~]# seq 8 | sed -n '1~2d' 因为d已经删除模式空间内容,再加-n就删除了原本的echo效果
[root@centos8 ~]# seq 8 | sed '1~2d'
2
4
6
8
[root@centos8 ~]# seq 8 | sed '2~2d'
1
3
5
7
=
3 实现 grep
6范例:使用/pattern/
实现【特定行】的匹配(类似grep)
[root@centos8 ~]# ip a | sed -n '/inet/p' # 此处 p 是script命令!!
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
inet 10.0.0.8/24 brd 10.0.0.255 scope global noprefixroute ens160
inet6 fe80::e016:ece6:7e36:e2ec/64 scope link noprefixroute
[root@centos8 ~]# df|sed -n '/^\/dev\/sd/p' # 此处 p 是script命令!!
/dev/sda2 104806400 3728680 101077720 4% /
/dev/sda5 52403200 398892 52004308 1% /data
/dev/sda1 999320 106688 823820 12% /boot
=
4 多点编辑⭐
7范例:多点编辑(两种方式)
# 取出除3、5、7以外的行
[root@centos8 ~]# seq 8 | sed -e '3d' -e '5d' -e '7d'
1
2
4
6
8
# 取出除1、2、5以外的行
[root@centos8 ~]# seq 8 | sed '1d;2d;5d'
3
4
6
7
8
注:以上都是以打印命令 p 进行演示,换成删除命令 d 都同理
如:批量删除指定行
sed '/^$/d' file 删除所有空行
sed '1,10d' file 删除1~10行
=
=
4.3 sed 核心功能
对文件内容进行编辑!同时可对原文件进行备份【核心功能】
- 可选择是否备份,直接
-i
表示修改;-i.bak
表示备份并修改(注意格式:-i
后面直接紧挨着指定后缀) - 应该注意到,此选项是确实修改了文件内容。其余选项都是将处理结果输出,原文件并不改变
-i
与其他选项一起使用时,必须位于最后一个(常用-ri
)!!!(类似tar xvf
的f
必须在最后)- 尽量不要与
-n
合用。。。否则容易改错文件
=
1 指定范围备份
[root@centos8 ~]# cat seq.log
1
2
3
4
5
6
[root@centos8 ~]# sed -i.bak '2d;4d;5d' seq.log
[root@centos8 ~]# ll se*
-rw-r--r--. 1 root root 6 Aug 11 11:45 seq.log
-rw-r--r--. 1 root root 12 Aug 11 11:44 seq.log.bak # 备份成功
[root@centos8 ~]# cat seq.log.bak
1
2
3
4
5
6
[root@centos8 ~]# cat seq.log
1
3
6
=
2 编辑文件内容
输出编辑后的内容【核心功能】
# 只显示非#开头的行
[root@centos8 ~]# sed -n '/^#/!p' /etc/fstab
UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0
UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2
UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0
UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0
注:'/^#/!p'与'/^[^#]/p'逻辑相同,但后者会过滤掉空行
# 删除所有以#开头的行
[root@centos8 ~]# sed '/^#/d' fstab
UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0
UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2
UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0
UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0
=
3 插入与替换
在匹配到的行上下插入新行,或替换之【核心功能】
sed '/root/a\superman' /etc/passwd 在匹配行的下一行插入新一行,内容为superman
sed '/root/i\superman' /etc/passwd 在匹配行的上一行插入新一行,内容为superman
sed '/root/c\superman' /etc/passwd 将匹配到的行内容替换为superman
# 注意:aic之后的 \ 可省略,但必须留出这个位置的空格!!!!!
注:【nl命令】对文本逻辑排序,显示行号
[root@centos8 ~]# nl /etc/passwd|sed '2a \tea'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
tea
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
..........
[root@centos8 ~]# nl /etc/passwd|sed '2c tea' # 省略斜线也可
1 root:x:0:0:root:/root:/bin/bash
tea
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
..........
=
4 -i
误操作演示
# 文件caokunzi内容很多,现在只想把 ssl 替换为caokunzi
# 1 查看原始内容
[root@jacklee ~]#grep -n ssl caokunzi
29: listen 443 ssl;
32: ssl_certificate /etc/nginx/ssl/5267479__kmelearning.com.pem;
33: ssl_certificate_key /etc/nginx/ssl/5267479__kmelearning.com.key;
34: ssl_session_timeout 5m;
# 2 测试修改
[root@jacklee ~]#sed -n s/ssl/caokunzi/p caokunzi
listen 443 caokunzi;
caokunzi_certificate /etc/nginx/ssl/5267479__kmelearning.com.pem;
caokunzi_certificate_key /etc/nginx/ssl/5267479__kmelearning.com.key;
caokunzi_session_timeout 5m;
# 3 此时 -n 与 p 的组合实际上并未修改源文件
[root@jacklee ~]#sed -n s/ssl/caokunzi/p caokunzi && grep -n ssl caokunzi
listen 443 caokunzi;
caokunzi_certificate /etc/nginx/ssl/5267479__kmelearning.com.pem;
caokunzi_certificate_key /etc/nginx/ssl/5267479__kmelearning.com.key;
caokunzi_session_timeout 5m;
29: listen 443 ssl;
32: ssl_certificate /etc/nginx/ssl/5267479__kmelearning.com.pem;
33: ssl_certificate_key /etc/nginx/ssl/5267479__kmelearning.com.key;
34: ssl_session_timeout 5m;
# 若使用 -n -i 组合(一种错误的演示)
[root@jacklee ~]#sed -ni s/ssl/caokunzi/p caokunzi
[root@jacklee ~]#cat -n caokunzi
1 listen 443 caokunzi;
2 caokunzi_certificate /etc/nginx/ssl/5267479__kmelearning.com.pem;
3 caokunzi_certificate_key /etc/nginx/ssl/5267479__kmelearning.com.key;
4 caokunzi_session_timeout 5m;
'发现此4行已经修改。但是源文件其他内容都被删除!!!只剩编辑过的4行
#》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
# 正确姿势:
sed -i s/ssl/caokunzi/ caokunzi
--------------------------------
'下列错误的共同点:若不加 -i 时会输出什么,则加上 -i 之后源文件就会被修改成什么
# 错误1:(-n 和 p)与 -i 共用
导致后果:源文件只剩编辑行
# 错误2:(-n)与 -i 共用
导致后果:源文件所有内容清空
# 错误3:(p)与 -i 共用
导致后果:编辑成功,但是所有编辑行都在原位置下方被复制了新的一行
=
=
4.4 特殊命令:搜索替换 s / / /⭐
1 重要说明
- 搜索替换只是一个script命令,前面还可以被地址条件限制
但实际使用一般不限定地址,表示全文搜索匹配并进行替换 - script命令在一次操作中只能有一个,但是命令
s///
的修饰符g/p
可同时使用(与选项 -n 配合)!!!
2 格式详解
s/pattern/string/修饰符
查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
替换修饰符:
g 行内全局替换 '一行之内可能有多处匹配,不加 g 表示只处理第一处'
p 输出替换成功的行
w /PATH/FILE 将替换成功的行保存至文件中
# 注意区别:s///是一个script命令,与 p 是同级别的命令(命令p表示打印模式空间内容)
# 但由于script命令只能有一个,为了不影响输出功能,为s///设置了一个修饰符p,作为命令p的填补
=
3 用法演示(包括 & )
# 常规用法:
# 将文件example全部内容中的test替换为mytest
sed 's/test/mytest/g' example # 也可表示为's/test/my&/'(而且是全局替换)
上述命令为什么能实现全文处理:
因为没限定地址:处理每一行
因为修饰符g:每一行的每一处都不放过
-------------------------------------------------------------------------
-------------------------------------------------------------------------
#【字符 & 的用法】
# 对有root的行 的第一个root 的后方追加superman
sed -n 's/root/&superman/p' /etc/passwd
# 对有root的行 的第一个root 的前方追加superman
sed -n 's/root/superman&/p' /etc/passwd
-------------------------------------------------------------------------
-------------------------------------------------------------------------
#【编辑与备份】
# 将文件 pets 中的所有dog换为cat ,所有hi换为lo ,并输出编辑后的全文【未修改内容】
sed -e 's/dog/cat/g' -e 's/hi/lo/g' pets
# 将文件 pets 备份为pets.bak,且所有dog换为cat,并输出编辑后的全文【备份并修改内容】
sed -i.bak 's/dog/cat/g' pets
=
4 重要范例⭐
帮助理解 -n 与修饰符 p 的关系(与命令 p 如出一辙)
# 替换并输出全文:
[root@CentOS8 ~]#sed 's/UUID/zhubazi/' fstab
#
# /etc/fstab
# Created by anaconda on Mon Sep 28 03:51:16 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
zhubazi=2452b617-9a10-488d-bc1e-074d216be0b4 / xfs defaults 0 0
zhubazi=f74fb060-143a-40a7-b53e-6e32250d5660 /boot ext4 defaults 1 2
zhubazi=a5ce2733-7c85-47ab-8db0-7a182668ead7 /data xfs defaults 0 0
zhubazi=849b755d-9106-4d9c-86d2-4e559c342356 swap swap defaults 0 0
#》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
# 替换并输出全文,且匹配行全部重复(未使用 -n 的结果)
[root@CentOS8 ~]#sed 's/UUID/zhubazi/p' fstab
#
# /etc/fstab
# Created by anaconda on Mon Sep 28 03:51:16 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
zhubazi=2452b617-9a10-488d-bc1e-074d216be0b4 / xfs defaults 0 0
zhubazi=2452b617-9a10-488d-bc1e-074d216be0b4 / xfs defaults 0 0
zhubazi=f74fb060-143a-40a7-b53e-6e32250d5660 /boot ext4 defaults 1 2
zhubazi=f74fb060-143a-40a7-b53e-6e32250d5660 /boot ext4 defaults 1 2
zhubazi=a5ce2733-7c85-47ab-8db0-7a182668ead7 /data xfs defaults 0 0
zhubazi=a5ce2733-7c85-47ab-8db0-7a182668ead7 /data xfs defaults 0 0
zhubazi=849b755d-9106-4d9c-86d2-4e559c342356 swap swap defaults 0 0
zhubazi=849b755d-9106-4d9c-86d2-4e559c342356 swap swap defaults 0 0
#》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
#【替换但不输出处理结果】此操作无意义!!!(因为只有 -i 才能真正修改内容)
sed -n 's/UUID/zhubazi/' fstab
#》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
# 替换且只输出匹配行(-n 与 p 组合)
[root@CentOS8 ~]#sed -n 's/UUID/zhubazi/p' fstab
zhubazi=2452b617-9a10-488d-bc1e-074d216be0b4 / xfs defaults 0 0
zhubazi=f74fb060-143a-40a7-b53e-6e32250d5660 /boot ext4 defaults 1 2
zhubazi=a5ce2733-7c85-47ab-8db0-7a182668ead7 /data xfs defaults 0 0
zhubazi=849b755d-9106-4d9c-86d2-4e559c342356 swap swap defaults 0 0
4.5 扩展正则的sed运用
1 取IP
从命令ip a
取IP地址:(9表示匹配第9行)
'至少一个非数字,接(一个以上数字或.连续出现),接任意内容
[root@centos8 ~]#ip a | sed -nr "9s/[^0-9]+([0-9.]+).*/\1/p"
10.0.0.8
'以至少一个非数字开头,接(一个以上数字或.连续出现),接任意内容 此方法可简化为1
[root@centos8 ~]#ip a | sed -nr '9s/^[^0-9]+([0-9.]+).*$/\1/p'
10.0.0.8
最佳:'至少一个非数字,接(连续出现的7~15个数字或.),接任意内容
[root@centos8 ~]#ip a | sed -nr '9s/[^0-9]+([0-9.]{7,15}).*/\1/p'
10.0.0.8
'利用具体内容前后夹逼
[root@centos8 ~]#ip a | sed -nr '9s/(.*inet )([0-9].*)(\/.*)/\2/p'
10.0.0.8
'使用两次 s///的空白替换(删除)功能,前后夹逼删除
[root@centos8 ~]#ip a | sed -n '9s/.*inet //;9s/\/.*//p' #不必句首句尾锚定
10.0.0.8
[root@centos8 ~]#ip a | sed -n '9s/.*inet //p' | sed -n 's/\/.*//p' #管道后只剩一行,不需9s
10.0.0.8
=
2 取dirname
和basename
'关键: [^/]+ 至少一个不是 / 开头的字符(从左往右抓)
[root@centos8 ~]# echo /etc/sysconfig/network-scripts/ | sed -nr 's#(^/.*/)([^/]+/?)#\1#p'
/etc/sysconfig/
[root@centos8 ~]# echo /etc/sysconfig/network-scripts/ | sed -nr 's#(^/.*/)([^/]+/?)#\2#p'
network-scripts/
=
3 取文件的前缀和后缀
'关键:后缀中没有 字符.
[root@centos8 ~]# echo a.c-d.345.gz|sed -nr 's/(.+)\.([^.]+)/\1/p'
a.c-d.345
[root@centos8 ~]# echo a.c-d.345.gz|sed -nr 's/(.+)\.([^.]+)/\2/p'
gz
'使用grep
[root@centos8 ~]# echo a.c-d.345.gz|grep -Eo '.*\.'
a.c-d.345. #不够完美
[root@centos8 ~]# echo a.c-d.345.gz|grep -Eo '[^.]+$'
gz
=
4 去掉所有注释和空行
sed -r '/^(#|$)/d' /file
sed -r '/^#|^$/d' /file
完