sed 是 Linux 中提供的一个外部命令,是一个行(hang)编辑器,也叫流编辑器,非交互式的对文件内容进行增删改查的操作,只能在命令行输入编辑命令、指定文件名,然后在屏幕查看输出。

它和文本编辑器又本质的区别了,单从名字上来看,行编辑器和文本编辑器,前者将文件中的行作为编辑对象,后者将文件作为编辑对象。

工作原理

sed 命令将当前处理的行读入模式空间进行处理,处理完把结果输出,并清空模式空间。然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行。还有一个空间叫保持空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出。

这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据。

命令格式

sed [选项] '匹配行 操作动作' file

选项

选项 描述
-n 仅显示处理后的结果
-e 多重编辑,类似grep -e
-f 执行动作从文件读取
-i 修改源文件
-r 使用扩展正则表达式

操作动作

动作 描述
/要打印输出的匹配行/p 打印输出
s/要替换的字符/替换后的字符/ 替换字符串
/匹配追定行/a \新增内容 在指定行后新增一行,a后面可以接字符串,接的字符串就是新增一行的内容
/要取代的匹配行/c \取代行内容 替换匹配行为指定内容
/要删除的匹配行/d 删除,删除指定行
D 删除第一行
/指定行/i \新增内容 在指定行之前新增一行,i后面可以接字符串,接的字符串就是新增一行的内容
: label 定义标签
b label 分支到脚本中带有标签的位置,如果分支不存在则分支到脚本的末尾
t label 如果s///是一个成功的替换,才跳转到标签
h 复制(覆盖)模式空间到保持空间
H 追加模式空间到保持空间
I 忽略大小写匹配
g 复制(覆盖)保持空间到模式空间
G 追加保持空间到模式空间
x 交换模式空间和保持空间的内容
/匹配行/n 读取匹配行的下一行到模式空间
/匹配行/N 追加匹配行的下一行内容到模式空间,并以换行符\n分隔
l 输出模式空间的行,并显示控制字符$
n N 读取/追加下一行输入到模式空间
p 将某个选择的数据输出,通常与-n选项一起使用
P 输出第一行
q 立即退出sed脚本
/指定行/r 文件名 指定行后追加到内容来自一个文件中的全部内容
/指定行/w 文件名 将匹配行的内容写到文件中
! 取反、否定
& 引用已匹配字符串
/匹配行/= 输出匹配行的行号,使用$=可以获取文本中行的数量

匹配行

匹配行指令 描述
1~2 步长,从第1行开始,每2行进行操作
$ 匹配最后一行
2,5 从第2行开始匹配到第5行结束
1,+3 从第1行开始,向后3行进行操作
1,~3 从第1行开始,到3行结束

示例

示例文本

$ tail /etc/services
aigairserver    21221/tcp               # Services for Air Server
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery
ka-sddp         31016/tcp               # Kollective Agent Secure Distributed Delivery
edi_service     34567/udp               # dhanalakshmi.org EDI Service
axio-disc       35100/tcp               # Axiomatic discovery protocol
axio-disc       35100/udp               # Axiomatic discovery protocol
pmwebapi        44323/tcp               # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp               # ASSIA CloudCheck WiFi Management keepalive
cloudcheck      45514/tcp               # ASSIA CloudCheck WiFi Management System
spremotetablet  46998/tcp               # Capture handwritten signatures

$ tail /etc/services  > test.txt

以下所有的操作中加上选项 -i 则会直接修改文件内容,不加只会输出让你看到的内容变化,实际不修改文件内容。

输出打印(p)

# 输出以a开头的行
$ sed -n '/^a/p' test.txt
aigairserver    21221/tcp               # Services for Air Server
axio-disc       35100/tcp               # Axiomatic discovery protocol
axio-disc       35100/udp               # Axiomatic discovery protocol

# 输出第二行
$ sed -n '2p' test.txt
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery

# 输出2-5行
$ sed -n '2,5p' test.txt
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery
ka-sddp         31016/tcp               # Kollective Agent Secure Distributed Delivery
edi_service     34567/udp               # dhanalakshmi.org EDI Service
axio-disc       35100/tcp               # Axiomatic discovery protocol

替换(s///)

默认会替换文件中所有的匹配字符

# 替换 ka-kdp 为 FeiYi
$ sed 's/ka-kdp/FeiYi/' test.txt 

# 替换开头为 ka-kdp 的为 FeiYi,并只输出替换的行,-n和p结合使用
$ sed -n 's/^ka-kdp/FeiYi/p' test.txt
FeiYi          31016/udp               # Kollective Agent Kollective Delivery

新增(a/i/c)

# 在 ka-kdp 下一行添加 test
$ sed  '/ka-kdp/a \test' test.txt 
aigairserver    21221/tcp               # Services for Air Server
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery
test
ka-sddp         31016/tcp               # Kollective Agent Secure Distributed Delivery
edi_service     34567/udp               # dhanalakshmi.org EDI Service
axio-disc       35100/tcp               # Axiomatic discovery protocol
axio-disc       35100/udp               # Axiomatic discovery protocol
pmwebapi        44323/tcp               # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp               # ASSIA CloudCheck WiFi Management keepalive
cloudcheck      45514/tcp               # ASSIA CloudCheck WiFi Management System
spremotetablet  46998/tcp               # Capture handwritten signatures

# 在 ka-kdp 上一行添加 test
$ sed  '/ka-kdp/i \test' test.txt 
aigairserver    21221/tcp               # Services for Air Server
test
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery
ka-sddp         31016/tcp               # Kollective Agent Secure Distributed Delivery
edi_service     34567/udp               # dhanalakshmi.org EDI Service
axio-disc       35100/tcp               # Axiomatic discovery protocol
axio-disc       35100/udp               # Axiomatic discovery protocol
pmwebapi        44323/tcp               # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp               # ASSIA CloudCheck WiFi Management keepalive
cloudcheck      45514/tcp               # ASSIA CloudCheck WiFi Management System
spremotetablet  46998/tcp               # Capture handwritten signatures

# 将有字符串 axio 的行替换为 test
$ sed  '/axio/c \test' test.txt 
aigairserver    21221/tcp               # Services for Air Server
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery
ka-sddp         31016/tcp               # Kollective Agent Secure Distributed Delivery
edi_service     34567/udp               # dhanalakshmi.org EDI Service
test
test
pmwebapi        44323/tcp               # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp               # ASSIA CloudCheck WiFi Management keepalive
cloudcheck      45514/tcp               # ASSIA CloudCheck WiFi Management System
spremotetablet  46998/tcp               # Capture handwritten signatures

# 在指定行号下一行添加新一行
$ sed  '1a \test' test.txt 
aigairserver    21221/tcp               # Services for Air Server
test
ka-kdp          31016/udp               # Kollective Agent Kollective Delivery
ka-sddp         31016/tcp               # Kollective Agent Secure Distributed Delivery
edi_service     34567/udp               # dhanalakshmi.org EDI Service
axio-disc       35100/tcp               # Axiomatic discovery protocol
axio-disc       35100/udp               # Axiomatic discovery protocol
pmwebapi        44323/tcp               # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp               # ASSIA CloudCheck WiFi Management keepalive
cloudcheck      45514/tcp               # ASSIA CloudCheck WiFi Management System
spremotetablet  46998/tcp               # Capture handwritten signatures

删除(d)

# 删除带有 ka-kdp 的行
sed  '/ka-kdp/d' test.txt

# 删除最后一行
sed  '$d' test.txt

# 从第3行开始,每两行删一行
sed  '3~2d' test.txt

# 删除第2行和第3行
sed '2,3d' test.txt 

# 删除注释行和空行,例子中没有,可以随便给加一个
sed  -i -e '5a \#' -e '9G' test.txt
sed -i -e '/^#/d' -e '/^$/d' test.txt 

多重编辑(-e)

如上删除的例子中有 -e 的用法

有的地方说分号也可以达到-e的效果,如下,第一种可以,第二种不可以,我搞不懂,有大佬知道望告知,博主信息处有我的 QQ 联系方式。

sed '1,2d;3,4d' test.txt 
sed '5a \#; 6a \#' test.txt 

复制剪切粘贴操作(h/H/g/G/x)

h/H和g/G需要结合使用

# 复制ka-kdp一行,粘贴到cloudcheck-ping的一行并覆盖
sed -e '/ka-kdp/h' -e '/cloudcheck-ping/g' test.txt 

# 剪切效果,{h;d}表示先复制,再删除
sed -e '/ka-kdp/{h;d}' -e '/cloudcheck-ping/g' test.txt 

# 剪切并追加到最后
sed -e '/ka-kdp/{h;d}' -e '$G' test.txt 

# 交换位置,复制ka-kdp一行到cloudcheck-ping的位置覆盖,然后将cloudcheck-ping放到文本末尾
sed -e '/ka-kdp/h' -e '/cloudcheck-ping/x' -e '$G' test.txt 

空行(G)

单独使用G时,可用作添加空行

# 第一行后添加空行
sed '1G' test.txt 
# 匹配行后添加空行
sed '/cloud/G' test.txt 

忽略大小写匹配(I)

# s///g 是替换的操作动作,I是忽略大小写进行匹配,无论大小写的a都会被替换为1
sed 's/A/1/Ig' test.txt 

读取下一行(n和N)

n:读取下一行到模式空间

# 输出匹配行的下一行,匹配到的第一行的下一行,并不会进行全局匹配
$ seq 5 | sed -n '/3/{n;p}'
4

# 输出偶数行,读取第一行的1,执行n输出下一行的2,执行p打印出,读取3,执行n输出下一行的4,一次类推
$ seq 6 | sed -n 'n;p'
2
4
6

# 输出奇数行,原理是将偶数行删除后的输出
$ seq 6 | sed 'n;d'
1
3
5
$ seq 6 | sed -n 'p;n'
1
3
5

N:追加下一行内容到模式空间,并以换行符\n分隔

可以理解为,N可以将两行看成一组

# 使用q可以在N执行玩一次之后退出
$ seq 6 |sed 'N;q'
1
2
# 原理:
# sed读取第一行,N读取下一行,此时为1\n2,sed读取第三行,N读取第四行,此时为3\n4,类推
$ seq 6 | sed 'N;s/\n//'
12
34
56
# 原理:
# sed读取第一行,N读取下一行,此时为1\n2,s///将换行符\n替换为空,此时为12,类推

# 当结尾行号为奇数时,默认不输出
$ seq 5 | sed -n 'N;p'
1
2
3
4
# 原理:
# sed读取第一行,N读取下一行,此时为1\n2,sed读取第三行,N读取第四行,此时为3\n4
# sed读取第五行,N读取下一行,下一行并没有,所以sed会退出,不会再执行后面的p

# 输出结尾为奇数的行
$ seq 5 | sed -n '$!N;s/\n//;p'
12
34
5
# 原理:
# sed读取第一行,N读取下一行,此时为1\n2,sed读取第三行,N读取第四行,此时为3\n4
# sed读取第五行,此时$!N就发生了反应,$表示最后一行,!N表示不执行N
# 也就是不读取下一行,连起来就是读取到最后一行时不执行N,可以执行后面的p

打印和删除第一行(P/D)

P:打印第一行

D:删除第一行

说实话这里我没懂

# 输出奇数
$ seq 6 | sed -n 'N;P'
1
3
5

# 保留最后一行
$ seq 6 | sed 'N;D'
6

读取文件并追加到匹配行后(r)

$ cat 123
123

# 第三行后添加123文件中的内容
sed '3r 123' test.txt 

# 在匹配行后追加123文件中的内容 
sed '/axio/r 123' test.txt 

将匹配行写到文件(w)

$ sed '/axio/w 1.txt' test.txt 
$ cat 1.txt 
axio-disc       35100/tcp               # Axiomatic discovery protocol
axio-disc       35100/udp               # Axiomatic discovery protocol

标签(:、b和t)

标签可以控制流,实现分支判断。

: label name 定义标签

b label 跳转到指定标签,如果没有该标签则跳到脚本末尾

t label 跳转到指定标签,前提是s///命令执行成功

seq 6 | sed ':a;N;s/\n/,/;b a'
# :a  定义标签名为a
# sed读取第一行内容1
# N  将第一行的下一行内容追加到第一行,并以\n分隔,此时第一行为1\n2
# s/\n/,/ 此时第一行为1,2
# b a  跳转到a标签,也就是从N开始
# 此时的内容为
# 1,2
# 3
# 4
# 5
# 6
# sed读取第一行内容1,2
# N  将第一行的下一行内容追加到第一行,并以\n分隔,此时第一行为1,2\n3
# s/\n/,/ 此时第一行为1,2,3
# b a  跳转到a标签,也就是从N开始
# 此时的内容为
# 1,2,3
# 4
# 5
# 6
# 以次类推,直到内容为1,2,3,4,5,6时,N无法再读取下一行结束

seq 6 | sed ':a;N;$!b a;s/\n/,/g'
# :a  定义标签名为a
# sed读取第一行内容1
# N  将第一行的下一行内容追加到第一行,并以\n分隔,此时第一行为1\n2
# $!b a  表示读取到最后一行时,不执行b a,还没到最后一行,所以执行b a
# sed读取第一行内容为1\n2
# N  将第一行的下一行内容追加到第一行,并以\n分隔,此时第一行为1\n2\n3
# b a
# sed读取第一行内容为1\n2\n3
###直到内容变为1\n2\n3\n4\n5\n6
# $!b a 不再执行b a,也就是不会再跳回a标签的操作了,才会往后执行
# s/\n/,/g,将所有内容的\n替换为,

实例

# b1fffef17c17 变为 b1ff:fef1:7c17
$ echo "b1fffef17c17" | sed -r ':label;s/([^:]+)([0-9a-f]{4})/\1\:\2/;t label'
b1ff:fef1:7c17
# :label 定义标签
# s/([^:]+)([0-9a-f]{4})/\1\:\2/
# [^]是排除的意思
# ([^:]+),本条语句中排出了冒号不匹配,也可以理解为以冒号为分隔符进行匹配,遇到冒号就当作分隔符
# 冒号后作为第二行
# ([[0-9a-f]]{4}) 连续的4个字符为数字或者小写字母
# \1:\2 类似脚本的位置变量,在sed中表示为子匹配项的位置,本语句中([^:]+)为\1,([0-9a-f]{4})为\2
# 根据以下得出 \1:\2 = ([^:]+):([0-9a-f]{4}) = b1fffef1:7c17
$ echo "b1fffef17c17" | sed -rn 's/([^:]+)([0-9a-f]{4})/\1:\2/p'
b1fffef1:7c17

# 根据以上又可以得出,([0-9a-f]{4})的值为7c17,([^:]+)的值为b1fffef1
# 结果相当于是 “字符串:4个字符”
# 因为\2的匹配项,指定了4个字符的匹配,所以优先给限制字符个数的语句中匹配是通过倒序来的
# 如果将([0-9a-f]{4})和([^:]+)的位置互换,结果如下:
$ echo "b1fffef17c17" | sed -rn 's/([0-9a-f]{4})([^:]+)/\1:\2/p'
b1ff:fef17c17

# 当使用标签循环时,第二次sed读取的字符串位b1fffef1:7c17
# 上面说到遇到冒号就当作第二行来读取,sed读取就变成了
b1fffef1
7c17
# 很明显第二行不匹配([^:]+)([0-9a-f]{4})这样的正则,该正则至少5个字符串
# 所以只有b1fffef1符合特征,执行\1:\2的替换即可,同理得出
$ echo "b1fffef1" | sed -rn 's/([^:]+)([0-9a-f]{4})/\1:\2/p'
b1ff:fef1
# 经过循环得出的结果为b1ff:fef1:7c17

获取行号

# 获取axio所在行的行号
$ sed -n '/axio/=' test.txt
5
6

# 获取文本总行数
$ sed -n '$=' test.txt
5

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0