shell 流编辑器 sed

一、sed介绍

Linux中,常使用流编辑器sed 进行文本替换工作。与交互式编辑器(例如vim)不同,sed编辑器以批处理的方式来编辑文件。

一次从输入中读取一行数据

根据所提供的编辑器命令匹配数据

按照命令修改流中的数据

将新的数据输出到 STDOUT(标准输出,即显示器)

在sed编辑器匹配完一行数据后,它会读取下一行数据并重复这个过程,直到处理完所有数据

二、sed 语法

sed [options] edit_commands [file]

[ ]中的内容为可选可不选

Bash

注意: sed 和grep 不同,不管是否找到指定的模式,它的退出状态都是0,只有当命令存在语法错误时,sed的退出状态才是非0

常用选项

选项 功能

-n(silent) 使用安静(silent)模式。来自stdin的资料一般都会被列出到屏幕,加上-n后,则只有经过sed处理的行才会被列出

-e(expression) 允许多点编辑

-f(file) 将sed的动作写在一个文本内,-f filename 则可以执行filename内的sed动作。

-r(regexp) 支持扩展正则

-i(in place) 直接修改源文件

三、sed子命令

普通子命令 功能

a 追加

c 修改

i 插入

d 删除

w 将行写入文件

y 将字符转换为另一字符

p 打印

r 读入字符串到文件

q 退出sed

= 打印当前行号

s 替换

子命令取反

! 取反

Bash

flag标记

g 单行全局

p 打印

数字 操作到第几个匹配

Bash

高级子命令 功能

h 拷贝pattern space的内容到holding buffer

H 追加pattern space的内容到holding buffer

g 获得holding buffer中的内容,并替代当前pattern space中的文本

G 获得holding buffer中的内容,并追加到当前pattern space的后面

x 交换暂存缓冲区与模式空间的内容

n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令

N 追加新行到模式空间

P 打印模式空间中的第一行

D 删除模式空间的第一行,会导致sed从开头重新执行所有子命令

1.定址

默认sed 对文件中的所有行进行编辑。当然,也可以只指定特定的某些行,或者行范围进行流编辑,这需要用到行寻址。所指定的行地址放在子命令之前

[address]commands

Bash

数字定址

sed 编辑器将文本流中的每一行都进行编号,第一行的编号为1 ,后面的按顺序分配0行号,通过指定特定的行号,可以选择编辑特定的行

cat -n file 中 -n是为了显示行号

[root@localhost ~]# cat -n test.txt | sed '3 s/bin/BIN/g' //将第三行中所有的 bin 替换成 BIN

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

Shell

[root@localhost ~]# cat -n test.txt |sed '2,5 s/bin/BIN/g' //将第2到5行中所有的 bin 替换成 BIN

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

Shell

$ 在正则中是匹配行尾

[root@localhost ~]# cat -n test.txt |sed '2,$ s/bin/BIN/g' //将第2行到尾行中所有的 bin 替换成 BIN

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

Shell

正则定址

sed 编辑器允许使用正则过滤出命令要作用的行

/pattern/command

Bash

必须使用/ 将要指定的 pattern 包起来

sed 会寻找匹配文本模式的行,然后对这些行执行编辑命令

sed -n 中 -n是静默输出,只输出经过sed处理的行

[root@localhost ~]# sed -n '/root/s/bin/BIN/p' /etc/passwd //寻找包含有字符串 root 的行,并且将匹配行中的 bin 替换为 BIN

root:x:0:0:root:/root:/BIN/bash

operator:x:11:0:operator:/root:/sBIN/nologin

Shell

[root@localhost ~]# sed -n '/root/,/nologin/ s/bin/BIN/p' /etc/passwd //寻找包含有字符串 root 或 nologin 的行,并且将匹配行中的 bin 替换为 BIN

root:x:0:0:root:/root:/BIN/bash

BIN:x:1:1:bin:/bin:/sbin/nologin

operator:x:11:0:operator:/root:/sBIN/nologin

games:x:12:100:games:/usr/games:/sBIN/nologin

Shell

2.子命令使用

1、s 替换

使用s命令来进行文本替换操作

[root@localhost ~]# cat aaa.txt | sed 's/bin/BIN/'

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

Shell

/字符为界定符,用于分隔字符串(sed 编辑器允许使用其他字符作为替换命令中的字符串分隔符)

使用#作为字符串分隔符

[root@localhost ~]# cat aaa.txt | sed 's#bin#BIN#'

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

Shell

数字指明替换掉第几次匹配到的文本

没有设置这个标记时,默认是替换第一次匹配的文本

将aaa.txt中每行的第2个bin 替换为 BIN

[root@localhost ~]# cat aaa.txt | sed 's/bin/BIN/2'

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

Shell

2、g替换所有匹配到的文本

将aaa.txt 中的 bin 全部替换为 BIN

[root@localhost ~]# cat aaa.txt | sed 's/bin/BIN/g'

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

Shell

3、p打印与替换命令中指定模式(srcStr)相匹配的行

使用显示行号可以看出含有bin的行被输出了两次

一次是 sed 编辑器自动输出的

另一次则是 p 标记打印出来的匹配行

[root@localhost ~]# cat -n aaa.txt | sed 's/bin/BIN/p'

1 root:x:0:0:root:/root:/BIN/bash

1 root:x:0:0:root:/root:/BIN/bash

2 BIN:x:1:1:bin:/bin:/sbin/nologin

2 BIN:x:1:1:bin:/bin:/sbin/nologin

3 daemon:x:2:2:daemon:/sBIN:/sbin/nologin

3 daemon:x:2:2:daemon:/sBIN:/sbin/nologin

4 adm:x:3:4:adm:/var/adm:/sBIN/nologin

4 adm:x:3:4:adm:/var/adm:/sBIN/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sroot/nologin

6 sync:x:5:0:sync:/sBIN:/bin/sync

6 sync:x:5:0:sync:/sBIN:/bin/sync

Shell

将aaa.txt中所有的root 全部都替换成 ROOT,并输出被修改的行

[root@localhost ~]# cat -n aaa.txt | sed 's/root/ROOT/gp'

1 ROOT:x:0:0:ROOT:/ROOT:/bin/bash

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:/sROOT/nologin

5 lp:x:4:7:lp:/var/spool/lpd:/sROOT/nologin

6 sync:x:5:0:sync:/sbin:/bin/sync

Shell

如果想只输出被修改的部分可以使用sed -n静默输出

4、d删除

sed 编辑器使用 d 命令来删除文本流中的特定行。使用d命令时,一般需要带上位寻址,以删除指定的行,否则默认会删除所有文本行。

[root@localhost ~]# cat aaa.txt

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:/sroot/nologin

sync:x:5:0:sync:/sbin:/bin/sync

#使用d删除命令

[root@localhost ~]# cat aaa.txt |sed '/root/d'

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

sync:x:5:0:sync:/sbin:/bin/sync

Shell

删除第2到最后一行$

[root@localhost ~]# cat -n aaa.txt

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:/sroot/nologin

6 sync:x:5:0:sync:/sbin:/bin/sync

#使用命令后

[root@localhost ~]# cat -n aaa.txt |sed '2,$d'

1 root:x:0:0:root:/root:/bin/bash

Shell

插入追加修改文本

使用i命令在sed编辑器中来向数据流中插入文本行,该命令会在指定行前增加一个新行

使用a命令在sed编辑器中来向数据流中附加文本行,该命令会在指定行后增加一个新行

注意这两个命令都不能在单行上使用(即不是用来在一行中插入或附加一段文本的),只能指定插入还是附加到另一行

sed '[address][i | a] newline' file

Shell

[root@localhost ~]# sed 'i\Insert a line behind every line' /etc/passwd      # 向数据流的每一行前面增加一个新行,新行的内容为 \ 后面的内容

[root@localhost ~]# sed '1i\Insert a line behind the first line' /etc/passwd   # 在数据流的第一行前面增加一个新行

[root@localhost ~]# sed '3a\Append a line after the third line' /etc/passwd # 在数据流的第三行后面增加一个新行

[root@localhost ~]# sed '$a\Append a line in the last line' /etc/passwd      # 在数据流的最后一行后面增加一个新行

Shell

使用命令c可以将数据流中的整行文本修改为新的行,与插入、附加操作一样,这要求在 sed 命令中指定新的行

sed '[address][c] newtext' file

Shell

[root@localhost ~]# sed '3 c\New text' /etc/passwd     # 将数据流中第三行的内容修改为 \ 后面的内容

[root@localhost ~]# sed '/root/ c\New text' /etc/passwd  # 将匹配到 root 的行的内容修改为 \ 后面的内容

[root@localhost ~]# sed '2,4c\New text' /etc/passwd     # 将第2到4行的内容修改为 \ 后面的内容,但是不是逐行修改,而是会将这之间的 3 行用一行文本来替代

Shell

y逐字符转换

[address]y/inchars/outchars/

Shell

转换命令会对 inchars 和 outchars 的值进行一对一的映射。inchars 中的第一个字符会被转换成 outchars 中的第一个字符;inchars 中的第二个字符会被转换成 outchars 中的第二个字符;... 直到处理完一行。如果 inchars 和 outchars 的长度不同,则 sed 编辑器会产生一个错误消息。举个例子:

[root@localhost ~]# echo abcdefggfedcba | sed 'y/acg/ACG/'

AbCdefGGfedCbA

Shell

w保存数据到文件

[address]w filename

Shell

该语句将数据流的第 1、2 行写入文件 test.txt 中去

[root@qfedu.com ~]# sed '1,2w test.txt' /etc/passwd

[root@qfedu.com ~]# sed -n 's/root/ROOT/g w change.txt' /etc/passwd // 将 /etc/passwd 中所有的 root 都替换成 ROOT,并将被修改的行保存到文change.txt 中去

Shell

r从文件中读取数据

filename 为要插入的文件。r 命令常结合行寻址使用,以将文本插入到指定的行后面。

可以使用 r 命令来将一个文本中的数据插入到数据流中去,与普通的插入命令 i 类似,这也是对行进行操作的,命令格式如下:

[address]r filename

Shell

将文件 test.txt 中的内容插入到数据流第三行后面去。

[root@localhost ~]# sed '3 r test.txt' /etc/passwd

Shell

四、模式空间和保持空间

模式空间和保持空间是两个独立的缓冲区,可以进行交互,命令可以寻址模式空间但是不能寻址保持空间。

模式空间:容纳当前输入行的缓冲区,通过模式匹配到的行被读入模式空间中。用来进行进一步的操作;在多行模式中,'\n'可以用来和模式空间(N命令的结果)的任意换行符匹配,单模式空间底部的换行符除外。^匹配多行的首,$匹配多行的尾,不是每行的行首和行尾

保持空间:sed在处理文本的时候都是在模式空间中进行,但有时候有些复杂的操作单一的模式空间可能无法满足需求,于是就有了保持空间,这个空间通常是空闲的,并不处理数据,只在有需要的时候和模式空间进行一些必要的数据交换。

下面是模式空间中的常用命令。

h: 把模式空间中的内容覆盖至保持空间中

H:把模式空间中的内容追加至保持空间中

g: 从保持空间取出数据覆盖至模式空间

G:从保持空间取出内容追加至模式空间

x: 把模式空间中的内容与保持空间中的内容进行互换

多行模式空间

sed命令都是一行一行的进行处理文本的,不过有些时候单行处理可能并不能满足我们的需要,所以sed还提供了多行模式,多行模式的命令主要有 NPD 三个

N:读取匹配到的行的下一行追加至模式空间

P:打印模式空间开端至\n内容,并追加到默认输出之前

D:如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本, 并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间 不包含换行符,则会像发出d命令那样启动正常的新循环

1、示例

[root@qfedu.com ~]# cat /etc/passwd |sed -n '2{N;p}'

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

读取第二行的下一行,然后输出模式空间中的内容,此时模式空间中有两行

[root@qfedu.com ~]# cat /etc/passwd |sed -n '2{N;N;N;p}'

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

使用多个N命令可以读取多行进模式空间

Shell

[root@qfedu.com ~]# seq 1 6| sed -n '1,2H;4p;5{x;p}'

4

1

2

Shell

-n 是不显示默认输出内容,1,2H是将前两行追加至保持空间,4p显示第四行,5{x;p}是在第五行的时候交换保持空间和模式空间中的内容并且输出。注意输出中的空行,这是因为H命令追加的时候是添加换行符,由于保持空间默认是空的,所以添加换行符之后就多了一个空行。以用下面的命令先往保持空间覆盖一行然后追加。

[root@qfedu.com ~]# seq 1 6| sed -n '1h;2H;4p;5{x;p}'

4

1

2

Shell

第一个循环结束之后:模式空间为空,保持空间为第一行内容

第二个循环,将第二行追加到模式空间,此时模式空间为两行内容

第三个循环,没有匹配内容,不执行操作,模式空间和保持空间内容不变

第四个循环,读取第四行并输出,保持空间内容不变

第五个循环,读入第五行,然后和保持空间中的内容交换,之后输出。

暂存和取用命令:h H g G

[root@qfedu.com ~]# sed -r '1h;$G' /etc/hosts

[root@qfedu.com ~]# sed -r '1{h;d};$G' /etc/hosts

[root@qfedu.com ~]# sed -r '1h; 2,$g' /etc/hosts

[root@qfedu.com ~]# sed -r '1h; 2,3H; $G' /etc/hosts

暂存空间和模式空间互换命令:x

[root@qfedu.com ~]# sed -r '4h; 5x; 6G' /etc/hosts

Shell

对于模式空间和保持空间的个人见解

[root@localhost ~]# seq 1 6 |sed -n '1H;2p;3,5{x;p}'

2

1

3

4

Shell

首先,seq 1 6 是遍历1-6,sed -n是静默输出

1H是将1放入保持空间等待

2p是将2打印出来

3,5{x;p}是3到5依次去执行{x;p}

首先是3去交换已经在保持空间内的1,然后再打印,结果就是打印1

然后是4去交换刚被交换进去保持空间的3,然后打印,结果就是打印3

再然后5去交换在保持空间的4,继续打印,结果就是打印4

最后因为是静默输出所以结果就如上面,不执行sed的就不打印显示

相关推荐
cliffordl1 小时前
vscode 环境搭建
ide·vscode·编辑器
JANGHIGH1 小时前
VSCode引用Eigen库无法识别问题解决
ide·vscode·编辑器
猿饵块20 小时前
vscode
ide·vscode·编辑器
(⊙o⊙)~哦1 天前
vim的 配置文件
linux·编辑器·vim
卡兰芙的微笑1 天前
get_property --Cmakelist之中
前端·数据库·编辑器
我命由我123452 天前
2.使用 VSCode 过程中的英语积累 - Edit 菜单(每一次重点积累 5 个单词)
前端·javascript·ide·vscode·学习·编辑器·学习方法
wavemenu2 天前
在 Python 中使用 JSON
编辑器
guigui_hello2 天前
VScode的简单使用
c++·ide·vscode·编辑器
xuehaisj3 天前
健身器材识别系统源码分享
编辑器