sed的使用方法

sed的使用方法

sed文本处理:正则选定文本 -> sed进行处理

sed处理后并不会改变其内容

格式

命令行格式

1
sed [options] 'command' file(s)

主要参数:

  • options: -e,-n
  • command: 行定位(正则)+ sed命令(操作)

示例:

1
2
3
sed -n '/root/p'

sed -e '10,20d' -e 's/false/true/g'

脚本格式

1
sed -f scriptfile file(s)

基本操作命令

注意:增删改查等操作并不会真的修改文件本身,只是对输出进行修改而已

  • p : 打印相关的行
  • a : 新增行并输出(与vim的命令类似)
  • i : 插入行(与vim的命令类似)
  • c : 代替行(与vim的命令类似)
  • d : 删除行(与vim的命令类似)
  • s : 替换(核心参数) | g : 全局

p

passwd文件进行打印

1
sed 'p' passwd

但是你会发现这样直接打印出的结果所有行会被输出两次

应该加上-n参数

1
sed -n 'p' passwd

a(后)

第5行后添加分隔符

1
nl passwd | sed '5a========================='

第1-4行后添加分隔符

1
nl passwd | sed '1,4a========================='

i(前)

第5行前添加分隔符

1
nl passwd | sed '5i========================='

第1-4行前添加分隔符

1
nl passwd | sed '1,4i========================='

c

第10行进行替换

1
nl passwd | sed '10c hello'

第1-10行进行替换

1
nl passwd | sed '1,10c hello'

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
hello
11 games:x:12:100:games:/usr/games:/sbin/nologin
12 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13 nobody:x:99:99:Nobody:/:/sbin/nologin
14 systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
15 dbus:x:81:81:System message bus:/:/sbin/nologin
16 polkitd:x:999:997:User for polkitd:/:/sbin/nologin
17 abrt:x:173:173::/etc/abrt:/sbin/nologin
18 tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
19 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
20 chrony:x:998:996::/var/lib/chrony:/sbin/nologin
21 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
22 mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash

你会发现并不是一行行的进行替换,而是整体的替换为一个

d

删除第10行

1
nl passwd | sed '10d'

###s

将passwd文件每一行中的nologin替换为login

1
sed 's/nologin/login/' passwd

注意:不要忽略上面示例命令中的每一个/

将passwd文件中的每一个:替换为%

1
sed 's/:/%/' passwd

结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root%x:0:0:root:/root:/bin/bash
bin%x:1:1:bin:/bin:/sbin/nologin
daemon%x:2:2:daemon:/sbin:/sbin/nologin
adm%x:3:4:adm:/var/adm:/sbin/nologin
lp%x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync%x:5:0:sync:/sbin:/bin/sync
shutdown%x:6:0:shutdown:/sbin:/sbin/shutdown
halt%x:7:0:halt:/sbin:/sbin/halt
mail%x:8:12:mail:/var/spool/mail:/sbin/nologin
operator%x:11:0:operator:/root:/sbin/nologin
games%x:12:100:games:/usr/games:/sbin/nologin
ftp%x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody%x:99:99:Nobody:/:/sbin/nologin
systemd-network%x:192:192:systemd Network Management:/:/sbin/nologin
dbus%x:81:81:System message bus:/:/sbin/nologin
polkitd%x:999:997:User for polkitd:/:/sbin/nologin
abrt%x:173:173::/etc/abrt:/sbin/nologin
tss%x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
postfix%x:89:89::/var/spool/postfix:/sbin/nologin
chrony%x:998:996::/var/lib/chrony:/sbin/nologin
sshd%x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
mysql%x:27:27:MySQL Server:/var/lib/mysql:/bin/bash

每一行只替换了开头第一个冒号,这并不是我们想要得到的最后结果
怎么解决?
需要进行全局的替换操作

1
sed 's/:/%/g' passwd

结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root%x%0%0%root%/root%/bin/bash
bin%x%1%1%bin%/bin%/sbin/nologin
daemon%x%2%2%daemon%/sbin%/sbin/nologin
adm%x%3%4%adm%/var/adm%/sbin/nologin
lp%x%4%7%lp%/var/spool/lpd%/sbin/nologin
sync%x%5%0%sync%/sbin%/bin/sync
shutdown%x%6%0%shutdown%/sbin%/sbin/shutdown
halt%x%7%0%halt%/sbin%/sbin/halt
mail%x%8%12%mail%/var/spool/mail%/sbin/nologin
operator%x%11%0%operator%/root%/sbin/nologin
games%x%12%100%games%/usr/games%/sbin/nologin
ftp%x%14%50%FTP User%/var/ftp%/sbin/nologin
nobody%x%99%99%Nobody%/%/sbin/nologin
systemd-network%x%192%192%systemd Network Management%/%/sbin/nologin
dbus%x%81%81%System message bus%/%/sbin/nologin
polkitd%x%999%997%User for polkitd%/%/sbin/nologin
abrt%x%173%173%%/etc/abrt%/sbin/nologin
tss%x%59%59%Account used by the trousers package to sandbox the tcsd daemon%/dev/null%/sbin/nologin
postfix%x%89%89%%/var/spool/postfix%/sbin/nologin
chrony%x%998%996%%/var/lib/chrony%/sbin/nologin
sshd%x%74%74%Privilege-separated SSH%/var/empty/sshd%/sbin/nologin
mysql%x%27%27%MySQL Server%/var/lib/mysql%/bin/bash

ok,这样就解决了(形式跟vim的替换神似啊朋友们🤯)

行定位

定位一行:

  • x(行号)
  • /pattern/(正则)

x(行号)

示例:

1
sed -n '10p' passwd

如何确认是不是第十行呢?
可以这样做:

1
nl passwd | sed -n '10p'

/pattern/(正则)

如何打印包含特定字符有关的行呢?
比如你想在passwd文件中找到有root的行

1
sed -n '/root/p' passwd

定位n行:

  • x,y(行号)
  • /pattern/,/root/
  • x,y!(取反)
  • first~step(first表示从第几行开始,step表示间隔几行输出)

x,y(行号)

假如你想打印第10-20行

1
nl passwd | sed -n '10,20p'

结果如下:

1
2
3
4
5
6
7
8
9
10
11
10  operator:x:11:0:operator:/root:/sbin/nologin
11 games:x:12:100:games:/usr/games:/sbin/nologin
12 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13 nobody:x:99:99:Nobody:/:/sbin/nologin
14 systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
15 dbus:x:81:81:System message bus:/:/sbin/nologin
16 polkitd:x:999:997:User for polkitd:/:/sbin/nologin
17 abrt:x:173:173::/etc/abrt:/sbin/nologin
18 tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
19 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
20 chrony:x:998:996::/var/lib/chrony:/sbin/nologin

/pattern/,/root/

如果想要通过正则表达式的方式输出第10-20行
可以这样做:

1
nl passwd | sed -n '/operator/,/chrony/p'

你会发现,结果跟上面的命令结果一样
OK

x,y!(取反)

其实也可以通过取反的方式输出行

比如你不想输出第十行
可以这样写:

1
nl passwd | sed -n '10!p'

或者说你不想输出第10-20行
可以这样写:

1
nl passwd | sed -n '10,20!p'

first~step

间隔指定行数进行输出
比如从第一行开始每隔一行进行输出

1
nl passwd | sed -n '1~2p'

练习(1)

案例一:增加文件内容

在qq.txt文件中加入相应文本:
Port 52113
PermitRootLogin no
PermitEmptyPasswords no

1
sed '$a port52113 \npermitrootlogin no' qq.txt

假如说加入的这两行没有跟文本对齐
可以这样做:

1
sed '$a \    port52113 \n    permitrootlogin no' qq.txt

这样就在两行的前面各加上了四个空格
其中$a后面的\是转义字符,是为了与语句的空格区别开,\n表示换行

案例二:文本处理

删除文本中的空行

在qq.txt文件中随便加上几个空行,保存退出

1
sed '/^$/d' qq.txt

案例三:服务器日志处理

1
cat /var/log/yum.log

找出install信息

1
sed -n '/install/p' /var/log/yum.log

案例四:数据筛选

获取网卡的ip信息

首先看一下网卡的信息

1
ifconfig

结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
inet 192.168.43.254 netmask 255.255.255.0 broadcast 192.168.43.255
inet6 2409:8910:608:bee0:43c2:af5d:e823:ff1b prefixlen 64 scopeid 0x0<global>
inet6 fe80::d127:5715:bfe1:fad8 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d2:af:1d txqueuelen 1000 (Ethernet)
RX packets 564525 bytes 625035188 (596.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 280887 bytes 24583679 (23.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 44 bytes 3964 (3.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 44 bytes 3964 (3.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

然后利用替换把不需要的部分替换为空

1
ifconfig ens33 | sed -n '/inet /p' | sed 's/inet //' | sed 's/ net.*//'

高级操作命令

  • {} : 允许同时使用多个sed命令,用;分隔
  • n : 读取下一个输入行(用下一个命令处理)
  • & : 具体作用看示例
  • () : 与替换操作结合使用效果更佳呦
  • r : 复制指定文件插入到匹配行
  • w : 复制匹配行拷贝指定文件里
  • q : 退出sed

{}

将第10-20行删除并且把所有nologin替换为login

1
nl passwd | sed '{10,20d;s/nologin/login/g}'

n

其实n的用处跟first~step类似,只不过比它高级(装逼)😏

示例:

输出偶数行:

1
2
nl passwd | sed -n '{n;p}'
nl passwd | sed -n '2~2p'

输出奇数行:

1
2
nl passwd | sed -n '{p;n}'
nl passwd | sed -n '1~2p'

按照1,4,7,10进行输出

1
2
nl passwd | sed -n '{p;n;n}'
nl passwd | sed -n '1~3p'

按照3,6,9,12进行输出

1
2
nl passwd | sed -n 'n;n;p'
nl passwd | sed -n '3~3p'

按照2,5,8,11进行输出

1
2
nl passwd | sed -n 'n;p;n'
nl passwd | sed -n '2~3p'

&

将passwd文件中的用户名称后面加上一些空格

1
nl passwd | sed 's/[a-zA-Z_-]\+/&      /'

结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1  root      :x:0:0:root:/root:/bin/bash
2 bin :x:1:1:bin:/bin:/sbin/nologin
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
6 sync :x:5:0:sync:/sbin:/bin/sync
7 shutdown :x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt :x:7:0:halt:/sbin:/sbin/halt
9 mail :x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator :x:11:0:operator:/root:/sbin/nologin
11 games :x:12:100:games:/usr/games:/sbin/nologin
12 ftp :x:14:50:FTP User:/var/ftp:/sbin/nologin
13 nobody :x:99:99:Nobody:/:/sbin/nologin
14 systemd-network :x:192:192:systemd Network Management:/:/sbin/nologin
15 dbus :x:81:81:System message bus:/:/sbin/nologin
16 polkitd :x:999:997:User for polkitd:/:/sbin/nologin
17 abrt :x:173:173::/etc/abrt:/sbin/nologin
18 tss :x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
19 postfix :x:89:89::/var/spool/postfix:/sbin/nologin
20 chrony :x:998:996::/var/lib/chrony:/sbin/nologin
21 sshd :x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
22 mysql :x:27:27:MySQL Server:/var/lib/mysql:/bin/bash

案例一:大小写转换

将用户名的首字母转换为大写/小写

知识点
元字符\u\I\U\L : 转换为大写/小写

1
nl passwd | sed 's/[a-z_-]\+/\u&/' passwd

案例二:大小写转换

将文件夹下的.txt文件名转换为大写

首先看一下我的当前目录下有什么.txt文件

1
ls *.txt

结果为:

1
qq.txt  test.txt

那么接下来进行操作吧

1
ls *.txt | sed 's/\w\+/\U&/'

结果为:

1
2
QQ.txt
TEST.txt

也许你会奇怪为什么后面的txt没有被大写
其实是因为\w并不包括.,所以后面的内容便不再进行替换

()

与练习(1)中的案例四一样,获取网卡的ip
只不过方式有一些不同
究竟不同在哪里
请看例子(其实是我也迷迷糊糊,说不明白)…

1
ifconfig ens33 | sed -n '/inet /p' | sed 's/inet \([0-9.]\+\).*$/\1/'

大概来说一下吧,我的理解是被()括起来的部分会被保留,其余的会被替换为空白
此处只有一对(),所以后面要替换的位置只有一个\1
假如命令中有两处被括号括起来,也就是说
有两个地方想要被保留下来,那么后面要替换的位置就要这样写\1\2
究竟如何,我也不知道,先这样吧。

看一个案例吧…

案例:获取passwd文件信息

获取用户的名字,id,和组id

1
sed 's/^\([a-z_-]\+\):x:\([0-9]\+\):\([0-9]\+\).*$/USER:\1 \t ID:\2 \t  UID:\3/' passwd

r

在开始解析r的使用方法之前,首先创建两个文件

1
2
echo -e '3253152514\n12425352\n124135532355' > 123.txt
echo -e 'sdafaefasf\nfsafsffef\nsffdaawwa' > abc.txt

目标:将123.txt中的内容放入到abc.txt的内容的第一行后进行输出(不会改变原文件的内容)

1
sed '1r 123.txt' abc.txt

w

目标1:将abc.txt中的第一行文件改写到123.txt文件中

1
sed '1w 123.txt' abc.txt

目标2:将abc.txt中的全部内容文件改写到123.txt文件中

1
sed 'w 123.txt' abc.txt

你有没有发现w的写入操作是将被改写的文件内容全部覆盖?

q

目标:passwd文件中找到第一个nologin就停止输出

1
nl passwd | sed '/nologin/q'

本文标题:sed的使用方法

文章作者:尚先森

发布时间:2022年02月03日 - 20:23:03

最后更新:2022年07月27日 - 13:58:01

原始链接:https://imauu.gitee.io/2022/02/03/sed的使用方法/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

尚先森 wechat
有任何问题可以扫描上方二维码私聊我哦😊
您的支持是我创作的最大动力^_^