Skip to content

Menu
Menu

sed

Posted on 2021年12月4日2021年12月6日 by zhezimi

Sed是一个流编辑器。流编辑器用于在输入流(文件或管道输入)上执行基本文本转换。虽然在某些方面类似于允许脚本化编辑(如ed)的编辑器,但sed的工作原理是只对输入进行一次传递,因此效率更高。

语法:

sed OPTIONS… [SCRIPTS] [INPUTFILE…]

sed每次从INPUTFILE中读取一行记录,并在该记录上执行SCRIPT。

sed 首先从 INPUTFILE 中读取第一行,然后执行所有的SCRIPT;再读取第二行,执行所有 SCRIPT,重复这个过程,直到INPUTFILE 结束。

通过指定[OPTIONS] 还可以给 sed 传递一些可选的选项。

注意:

sed 绝不会修改原始文件 INPUTFILE,它只是将结果内容输出到标准输出设备。如果要保持变更,应该使用重定向 > filename.txt

OPTIONS概述:

-n,–quiet,–silent:抑制模式空间的自动打印

-e script,–expression=script:将脚本添加到要执行的命令中

-f script-file,–file=script-file:将脚本文件的内容添加到要执行的命令中

-i[SUFFIX],–in-place[=SUFFIX]:直接修改读取的文件内容,而不是由屏幕输出

-r,–regexp-extended:在脚本中使用扩展正则表达式。

-c, –copy:该选项应和-i 配合使用。使用-i 时,通常在命令执行完成后,sed 使用临时文件来保持更改 后的内容,然后把该临时文件重命名为输入文件。但这样会改变文件的所有者。配合c选项,可以保持文件所有者不变。也可以使 用–copy 来代替。

-l N, –line-length=N:指定行的长度,需要和 l 命令配合使用(注意选项 l 和命令 l,不要弄混了),使用-l 选项即指定行的长度。也可以使用–line-length 来代替.

SCRIPTS概述

sed程序由一个或多个sed commands组成,这些命令由一个或多个-e、-f、–expression和–file选项传递。

Sed commands遵循以下语法:

[addr]X[options]

X是一个单字母sed command。[addr]是一个可选的行地址。如果指定[addr],则X命令只对匹配的行执行。[addr]可以是一个单行号、一个正则表达式或一个行范围(参见下面的地址范围)。额外的 [options] 用于某些 sed commands。

下面的示例表示删除输入中的第30行到第35行。30、35是一个地址范围。d为delete命令:

sed ‘30,35d’ input.txt > output.txt

commands概述

GNU sed支持以下命令。一些是标准POSIX命令,而另一些是GNU扩展。

i text:在一行之前插入文本。

a text :在一行之后追加文本。

c text :用文本替换(更改)行。

d:删除模式空间。开始下一个循环。

e:执行在模式空间中找到的命令,并用输出替换模式空间;末尾换行符被抑制。

e command:执行命令并将其输出发送到输出流。该命令可以跨多行运行,但最后一行以反斜杠结尾。

F:(filename)打印当前输入文件的文件名(带一个换行符)。

g:将模式空间的内容替换为保持空间的内容。

G:复制/追加保持空间到模式空间。

h:(hold)用模式空间的内容替换保持空间的内容。

H:将换行符追加到保持空间的内容,然后将模式空间的内容追加到保持空间的内容。

l(小写的L):打印不可见字符,例如制表符\t,行尾标志$等,如果在l后面指定了数字,那么会在第n个字符处使用一个不可见自动折行。

n,N:将下一行输入读取/追加到模式空间。

p:打印模式空间的内容

P:输出到当前模式空间的第一个嵌入的换行符为止。

r filename :读取文件的文件名。

R filename:在当前周期结束或读取下一个输入行时,将要读取的文件名行放入队列并插入到输出流中。

s/regexp/replacement/[flags]:根据模式空间的内容匹配regexp。如果找到,用replacement替换匹配的字符串。

[flags]:

  • g:对regexp的所有匹配项应用替换,而不仅仅是第一个。
  • number:只替换regexp的第number个匹配项。
  • p:如果进行了替换,则打印新的模式空间。
  • w filename:如果进行了替换,则将结果写入指定的文件
  • e:代表执行,该标志可以将模式空间中的任何内容都当做shell来执行,并把命令执行的结果返回到模式空间,该标志只有GNU Sed中才可使用
  • I,i:正则表达式匹配的I修饰符是一个GNU扩展,它使sed以不区分大小写的方式匹配regexp。

t label:(test)只在读取最后一个输入行或进行条件转移后,有成功的替换时才进行转移。这个标签可以省略,这样下一个循环就开始了。

w filename:将模式空间写入文件名

W filename:将模式空间中直到第一个换行符为止的部分写入给定的文件名

x:交换保留空间和模式空间的内容。

y /src/dst/:将模式空间中与源字符匹配的任何字符与dest字符中的相应字符进行音译

z(zap)该命令清空模式空间的内容。

#注释,直到下一个换行。

{cmd;cmd……}:将几个命令组合在一起。

=:输出当前输入行号(后跟换行符)。

:label 指定分支命令的标签位置(b, t, t)。

地址范围

Sed命令可以不指定地址,在这种情况下,命令将对所有输入行执行;

只有一个地址,在这种情况下,该命令只会对匹配该地址的输入行执行;

或者使用两个地址,在这种情况下,命令将对所有匹配从第一个地址开始并继续到第二个地址的行执行。

关于地址范围有三件事要注意:语法是addr1,addr2(即,地址用逗号分隔);addr1匹配的行总是被接受,即使addr2选择了更早的行;如果addr2是一个regexp,它将不会针对addr1匹配的行进行测试。

在地址(或地址范围)后面,在命令前面,加一个!可以插入,它指定只在地址(或地址范围)不匹配的情况下执行命令。

支持以下地址类型:

number:只匹配指定的行号。

first~step:匹配每一步从一行开始。例如,“sed -n 1~2p”将输出输入流中的所有奇数行,地址2~5将从第2行开始每5行匹配一次。首先可以是零;在本例中,sed的操作就像它等于step一样。(这是分机。)

$:匹配最后一行。

/regexp/:匹配符合正则表达式regexp的行。

0,addr2:以“匹配第一个地址”的状态开始,直到找到addr2。这类似于1,addr2,除了如果addr2匹配输入的第一行0,addr2形式将在其范围的结束,而1,addr2形式仍将在其范围的开始。这只在addr2是正则表达式时有效。

addr1,+N:将匹配addr1和addr1后面的N行。

addr1,~N:将匹配addr1和addr1后面的行,直到下一行的输入行号是N的倍数。

模式空间

Sed 有两个内置的存储空间:

  • 模式空间:如你所知,模式空间用于 sed 执行的正常流程中。该空间 sed 内置的一个缓冲区,用于存放,修改从输入文件读取的内容
  • 保持空间:保持空间是另外一个缓冲区,用来存放临时数据。Sed 可以在保持空间 和模式空间交换数据,但是不能在保持空间上执行普通的 sed 命令。我们已经讨论 过,每次循环读取数据过程中,模式空间的内容都会被清空,然而保持空间的内容 则保持不变,不会在循环中被删除。

退出状态

  • 0:成功完成。
  • 1:无效命令、无效语法、无效正则表达式或与——posix一起使用的GNU sed扩展命令。
  • 2:命令行中指定的一个或多个输入文件无法打开(例如,如果没有找到文件,或读取权限被拒绝)。继续处理其他文件。
  • 4:在运行时出现I/O错误或严重的处理错误,GNU sed将立即中止。

执行流程

Sed 脚本执行遵从下面简单易记的顺序:Read,Execute,Print,Repeat(读取,执行,打印,重复),简称 REPR

分析脚本执行顺序:

  • 读取一行到模式空间(sed 内部的一个临时缓存,用于存放读取到的内容)
  • 在模式空间中执行命令。如果使用了{ } 或 –e 指定了多个命令,sed 将依次执行每 个命令
  • 打印模式空间的内容,然后清空模式空间
  • 重复上述过程,直到文件结束


下面我们正式开始

这是我们的测试文件

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# cat /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

查找:

1:查看第一行

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘1 p’ /tmp/student.txt
1 zhangsan 男 20
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

#我们发现后面的几行也显示出来了,并且第1行显示了两次,那么怎么解决呢?我们加一个-n选项就可以了

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘1 p’ /tmp/student.txt
1 zhangsan 男 20

2:从第2行开始,查看到最后一行

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘2,$p’ /tmp/student.txt
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

3:只查看奇数行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘1~2p’ /tmp/student.txt
1 zhangsan 男 20
3 wangwu 男 22
5 zhaogang 男 22

4:只查看偶数行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘2~2p’ /tmp/student.txt
2 lisi 男 21
4 zhaoliu 女 23
6 lihong 女 22

5:查看匹配zhao的行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/zhao/p’ /tmp/student.txt
4 zhaoliu 女 23
5 zhaogang 男 22

6:查看匹配zhang或zhao的行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/zhang|zhao/p’ /tmp/student.txt
1 zhangsan 男 20
4 zhaoliu 女 23
5 zhaogang 男 22

7:查看1开头的行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/^1/p’ /tmp/student.txt
1 zhangsan 男 20

8:查看以22结尾的的有哪些行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/22$/p’ /tmp/student.txt
3 wangwu 男 22
5 zhaogang 男 22
6 lihong 女 22

9:查看1,3,5开头的行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/^[135]/p’ /tmp/student.txt
1 zhangsan 男 20
3 wangwu 男 22
5 zhaogang 男 22

10:查看匹配wangwu后面的2行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/wangwu/,+2p’ /tmp/student.txt
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22

11:查看从第一次匹配wangwu的行到第4行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/wangwu/,4p’ /tmp/student.txt
3 wangwu 男 22
4 zhaoliu 女 23

12:打印匹配zhangssan的行开始到匹配zaholiu的行之间的所有内容

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘/zhangsan/,/zhaoliu/ p’ /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23

替换:

1:将zhangsan换成ZHANGSAN

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘s/zhangsan/ZHANGSAN/’ /tmp/student.txt
1 ZHANGSAN 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

2:只把匹配zhangsan的行的a替换成大写A

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘/zhangsan/s/a/A/’ /tmp/student.txt
1 zhAngsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

#我们发现zhangsan的第一个a替换成了大写A,第二个没有替换,如果要全部替换,就需要加上-g选项

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘/zhangsan/s/a/A/g’ /tmp/student.txt
1 zhAngsAn 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

3:匹配zhangsan的行的第二个a替换成大写A

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘/zhangsan/s/a/A/2’ /tmp/student.txt
1 zhangsAn 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

替换命令分界符:

上面的所有例子中,我们都是使用了sed的默认分界符/。如果在regexp或replacement中有/,那么需要使用反斜杠\来转移,下面我们来一个例子:

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ wwwroot]# cat path.txt
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

1:我们将/root/bin替换成/zhangsan/bin

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ wwwroot]# sed ‘s/\/root\/bin/\/zhangsan\/bin/’ path.txt
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/zhangsan/bin

每个/前面都使用\转义,会显得很混乱。幸 运的是,你可以使用任何一个字符作为 sed 替换命令的分界符,如 | 或 ^ 或 @ 或者 !

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ wwwroot]# sed ‘s!/root/bin/!/zhangsan/bin!’ path.txt
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ wwwroot]# sed ‘s@/root/bin/@/zhangsan/bin@’ path.txt
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

&的作用——获取匹配到的模式:

当在 replacement-string 中使用&时,它会被替换成匹配到的 original-string 或正则表达式。

1:当每行开头的数字需要加上[]

[root@iZ2ze9v82ax0ox0j12ahfhZ wwwroot]# sed “s/^[1-9]/[&]/g” /tmp/student.txt
[1] zhangsan 男 20
[2] lisi 男 21
[3] wangwu 男 22
[4] zhaoliu 女 23
[5] zhaogang 男 22
[6] lihong 女 22

2:1:当每行开头的数字需要加上0

[root@iZ2ze9v82ax0ox0j12ahfhZ wwwroot]# sed “s/^[1-9]/0&/g” /tmp/student.txt
01 zhangsan 男 20
02 lisi 男 21
03 wangwu 男 22
04 zhaoliu 女 23
05 zhaogang 男 22
06 lihong 女 22

删除

1:删除第1行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘1 d’ /tmp/student.txt
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

2:删除第1行到第3行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘1,3 d’ /tmp/student.txt
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

3:删除匹配zhao的行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘/zhao/ d’ /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
6 lihong 女 22

4:删除1开头的行

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘/^1/ d’ /tmp/student.txt
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

追加

语法:sed ‘[address] a the-line-to-append’ input-file

1:在匹配zhansan的行后面追加

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘/zhangsan/a 1.1 wanglun 男 18’ /tmp/student.txt
1 zhangsan 男 20
1.1 wanglun 男 18
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

2:在第2行后面追加

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘2a 1.1 wanglun 男 18’ /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
1.1 wanglun 男 18
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

3:在结尾追加

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘$a 1.1 wanglun 男 18’ /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22
1.1 wanglun 男 18

插入

语法:sed ‘[address] i the-line-to-insert’ input-file

插入命令 insert 命令和追加命令类似,只不过是在指定位置之前插入行

修改

语法:sed ‘[address] c the-line-to-insert’ input-file

1:换掉最后一行

[root@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘$c 1.1 wanglun 男 18’ /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
1.1 wanglun 男 18

多命令

你也可以把多 个 sed 命令合并到一个文件中,这个文件被称为 sed 脚本,然后使用-f 选项调用它。也可以使用 –e 选项,执行多个 sed 命令

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n -e ‘/^[1]/p’ -e ‘/^[3]/p’ -e ‘/^[5]/p’ /tmp/student.txt
1 zhangsan 男 20
3 wangwu 男 22
5 zhaogang 男 22

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n -f /tmp/testscript.sed /tmp/student.txt
1 zhangsan 男 20
3 wangwu 男 22
5 zhaogang 男 22
[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# cat /tmp/testscript.sed
/^[1]/p
/^[3]/p
/^[5]/p

打印模式空间(命p)

使用命令p,可以打印当前模式空间的内容。

sed在执行命令后或默认打印模式空间的内容,那么为什么还需要命令p呢?

有如下原因,命令p可以控制只输出你制定的内容,通常使用p时,还需要使用-n选项来屏蔽sed的默认输出,否则当执行命令p时,每行记录会输出两次。

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed ‘p’ /tmp/student.txt
1 zhangsan 男 20
1 zhangsan 男 20
2 lisi 男 21
2 lisi 男 21
3 wangwu 男 22
3 wangwu 男 22
4 zhaoliu 女 23
4 zhaoliu 女 23
5 zhaogang 男 22
5 zhaogang 男 22
6 lihong 女 22
6 lihong 女 22

[zhangsan@iZ2ze9v82ax0ox0j12ahfhZ ~]# sed -n ‘p’ /tmp/student.txt
1 zhangsan 男 20
2 lisi 男 21
3 wangwu 男 22
4 zhaoliu 女 23
5 zhaogang 男 22
6 lihong 女 22

参考链接:

https://linux.die.net/man/1/sed

https://www.gnu.org/software/sed/manual/sed.html#sed-addresses

相关文章

  • 排查网络故障常用命令

  • Linux 性能问题排查思路

  • 网络I/O模型

  • grep

  • 《shell脚本攻略》笔记

发表评论 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

近期文章

  • 排查网络故障常用命令
  • PHP-FPM异常问题
  • RabbitMQ 1:介绍
  • 观察者模式
  • 装饰者模式

近期评论

没有评论可显示。

分类

  • cdn
  • css
  • docker
  • git
  • http
  • javascript
  • linux
  • mysql
  • nginx
  • php
  • RabbitMQ
  • 代码规范
  • 性能
  • 正则表达式
  • 网络协议
  • 设计模式
© 2025 | Powered by Minimalist Blog WordPress Theme