3.sed 使用手册
sed 介绍
文章目录
- [3.sed 使用手册](#3.sed 使用手册)
-
- [sed 介绍](#sed 介绍)
- [sed 工作流程](#sed 工作流程)
- [sed 注意事项](#sed 注意事项)
- [sed 命令语法](#sed 命令语法)
-
- 准备文件
- [-e 选项](#-e 选项)
- [-n 选项](#-n 选项)
- [sed 行寻址](#sed 行寻址)
- [sed 子命令](#sed 子命令)
sed,英文全称 stream editor ,是一种非交互式的流编辑器,能够实现对文本非交互式的处理,功能很强大。
Linux操作文本的三大利器,简称三剑客,分别是:
- grep:擅长过滤。
- sed:擅长修改文本。
- awk:擅长格式化输出。
sed 与 awk 并称为 Linux/Unix 世界的两大王牌文字处理器:
- sed 侧重点是替换。
- awk 侧重点是分割和重新合成。
sed 工作流程
sed 工作流程,说起来很简单。
读取行 -> 执行 -> 显示 -> 读取行 -> 执行 -> 显示 -> .... -> 读取行 -> 执行 -> 显示

-
读取行
sed 从输入流 (文件、管道、标准输入流)中读取 一行 并存储在名叫
pattern space的内部空间中。sed 是行文字处理器。每次只会读取一行。
sed 内部会有一个计数器,记录着当前已经处理多少行,也就是当前行的行号。
-
执行
按照 sed 命令定义的顺序依次应用于刚刚读取的 一行 数据。
默认情况下,sed 一行一行的处理所有的输入数据。但如果我们指定了行号,则只会处理指定的行。
-
显示
把经过 sed 命令处理的数据发送到输出流(文件、管道、标准输出),并同时清空
pattern space空间。 -
上面流程一直循环,直到输入流中的数据全部处理完成。
sed 注意事项
整个流程看似简单,有几个知识点需要注意:
-
pattern space空间是 sed 在内存中开辟的一个私有的存储区域。内存的特性,会导致关闭命令行或关机数据就没了。 -
默认情况下,sed 命令只会处理
pattern space空间中的数据,且并不会将处理后的数据保存到源文件中。也就是说,sed 默认并不会修改源文件。但 GNU SED 提供提供了一种方式用于修改 源文件 。方式就是传递
-i选项,在后面的章节中介绍。 -
sed 还在内存上开辟了另一个私有的空间
hold space用于保存处理后的数据以供以后检索。每一个周期执行结束,sed 会清空
pattern space空间的内容,但hold space空间的内容并不会清空。hold space空间用于存储处理后数据,sed 命令并不会对这里的数据处理。这样,当 sed 需要之前处理后的数据时,可以随时从
hold space空间读取。 -
sed 程序执行前,模式
pattern和hold space空间都是空的。 -
如果我们没有传递任何输入文件,sed 默认会从 标准输入 中读取数据。
-
sed 可以指定只处理输入数据中的行范围。默认情况下是全部行,因此会依次处理每一行。
sed 命令语法
bash
-n, --quiet, --silent 取消自动打印模式空间
-e 脚本, --expression=脚本 添加"脚本"到程序的运行列表
-f 脚本文件, --file=脚本文件 添加"脚本文件"到程序的运行列表
--follow-symlinks 直接修改文件时跟随软链接
-i[扩展名], --in-place[=扩展名] 直接修改文件(如果指定扩展名就备份文件)
-l N, --line-length=N 指定"l"命令的换行期望长度
--posix 关闭所有 GNU 扩展
-r, --regexp-extended 在脚本中使用扩展正则表达式
-s, --separate 将输入文件视为各个独立的文件而不是一个长的连续输入
-u, --unspaceed 从输入文件读取最少的数据,更频繁的刷新输出
--help 打印帮助并退出
--version 输出版本信息并退出
-a ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
-c ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
-d ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
-i ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
-p ∶列印,亦即将某个选择的资料印出。通常 p 会与参数 sed -n 一起运作~
-s ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法
bash
sed [option] [sed-command] [input-file]
总的来说 sed 命令主要由四部分构成:
sed命令。[option]命令行选项,用于改变 sed 的工作流程。[sed-command]是具体的 sed 命令。[input-file]输入数据,如果不指定,则默认从标准输入中读取。
准备文件
bash
[root@server ~ 11:12:34]# cat > data.txt <<'EOF'
> I am studing sed
> I am www.laoma.cloud
> I am a Superman
> I am so handsome
> EOF
#不指明,直接打印
[root@server ~ 11:26:37]# sed '' data.txt
I am studing sed
I am www.laoma.cloud
I am a Superman
I am so handsome
-e 选项
从命令行读取sed命令,我们需要将 sed 命令使用单引号 ( '' ) 引起来。
bash
#删除第一行
[root@server ~ 11:30:04]# sed '1d' data.txt
I am www.laoma.cloud
I am a Superman
I am so handsome
#删除第一行和第二行
[root@server ~ 11:30:11]# sed '1d;2d' data.txt
I am a Superman
I am so handsome
#或者
[root@server ~ 11:30:34]# sed -e '1d' -e '2d' data.txt
I am a Superman
I am so handsome
-n 选项
如果指定了该选项,那么模式空间数据将不会自动打印,需要明确指明打印才会输出记录。
bash
[root@server ~ 11:30:40]# sed -n '' data.txt
#指明打印第一行
[root@server ~ 11:34:23]# sed -n '1p' data.txt
I am studing sed
#默认打印,再打印第一行
[root@server ~ 11:34:31]# sed '1p' data.txt
I am studing sed
I am studing sed
I am www.laoma.cloud
I am a Superman
I am so handsome
sed 行寻址
作用
通过行寻址匹配要处理的输入流。
语法
这里以打印命令p为例。
语法:[address1[,address2]]p
address1和address2分别是 起始地址 和 结束地址 ,可以是 行号 或 模式字符串。address1和address2都是可选参数,可以都不填,这时候就是打印所有行,从文件的开头到文件结束。- 如果存在一个,那么就是打印 单行 。也就是只打印
address1指定的那行。 p命令仅从 模式缓冲区 中打印行,也就是该行不会发送到输出流,原始文件保持不变。
示例文件
bash
[root@server ~ 13:33:18]# echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5 ' > test
演示
示例1: 打印所有行
bash
[root@server ~ 14:09:16]# cat test | sed ''
This is 1
This is 2
This is 3
This is 4
This is 5
[root@server ~ 14:09:32]# cat test | sed -n 'p'
This is 1
This is 2
This is 3
This is 4
This is 5
示例2: 打印特定行
bash
[root@server ~ 14:09:49]# cat test | sed -n '1p'
This is 1
示例3: 打印第1行到3行
bash
[root@server ~ 14:10:49]# cat test | sed -n '1,3p'
This is 1
This is 2
This is 3
示例4: 打印第3行到最后一行
bash
[root@server ~ 14:11:55]# cat test | sed -n '3,$p'
This is 3
This is 4
This is 5
示例5: 连续输出,打印第2行以及后续两行
bash
[root@server ~ 14:12:35]# cat test | sed -n '2,+2p'
This is 2
This is 3
This is 4
示例6: 隔行输出,打印第1行以及后续隔2行输出
bash
[root@server ~ 14:12:44]# cat test | sed -n '1~2p'
This is 1
This is 3
This is 5
sed 子命令
打印
作用
- p,打印模式空间所有记录。
- P,打印模式空间第一行记录。
语法
格式:[address1[,address2]]p
address1和address2分别是 起始地址 和 结束地址 ,可以是 行号 或 模式字符串。address1和address2都是可选参数,可以都不填,这时候就是打印所有行,从文件的开头到文件结束。- 如果存在一个,那么就是打印 单行 。也就是只打印
address1指定的那行。 p命令仅从 模式缓冲区 中打印行,也就是该行不会发送到输出流,原始文件保持不变。
示例
bash
[laoma@shell ~]$ cat << 'EOF' > ~/test
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
mail:x:8:12:mail:/var/spool/mail:/bin/false
ftp:x:14:11:ftp:/home/ftp:/bin/false
&nobody:$:99:99:nobody:/:/bin/false
zhangy:x:1000:100:,,,:/home/zhangy:/bin/bash
http:x:33:33::/srv/http:/bin/false
dbus:x:81:81:System message bus:/:/bin/false
hal:x:82:82:HAL daemon:/:/bin/false
mysql:x:89:89::/var/lib/mysql:/bin/false
aaa:x:1001:1001::/home/aaa:/bin/bash
ba:x:1002:1002::/home/zhangy:/bin/bash
test:x:1003:1003::/home/test:/bin/bash
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po
EOF
读取下一行
- n ,提前读取下一行,**覆盖**模型空间之前读取的行。模型空间之前读取的行并没有删除,依然打印至标准输出,除非使用-n选项指明不打印。
示例1:打印偶数行内容
bash
[root@server ~ 14:31:12]# echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5' | sed -n 'n;p'
This is 2
This is 4
说明:
- 读取
This is 1,执行n命令,此时模式空间为This is 2,执行p,打印模式空间内容This is 2。 - 之后读取
This is 3,执行 n 命令,此时模式空间为This is 4,执行p,打印模式空间内容This is 4。 - 之后读取
This is 5,执行 n 命令,因为后续没有内容了,所以退出,并放弃p命令。
因此,最终打印出来的就是偶数行。
- N ,简单来说就是**追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有\n换行符。**
示例1: 成对合并行
bash
[root@server ~ 14:30:46]# cat test | sed 'N;s/\n/==/'
root:x:0:0:root:/root:/bin/bash==bin:x:1:1:bin:/bin:/bin/false
...
说明:
N,追加下一行到当前行后面,组成一个新行来处理。s/\n/==/,将新行中\n换行符替换成==,末尾的换行符不替换。
示例2: 打印前2行
bash
[root@server ~ 14:30:25]# echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5' | sed -n '1{N;p}'
This is 1
This is 2
替换
**示例1:**把test文件中的root替换成tankzhang,只不过只替换一次即终止在这一行的操作,并转到下一行
bash
[root@server ~ 14:29:41]# sed 's/root/tankzhang/' test|grep tankzhang
tankzhang:x:0:0:root:/root:/bin/bash
关闭SELinux
bash
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' config
**示例2:**把test文件中的root全部替换成tankzhang。字母g是global的缩写。
bash
[root@server ~ 14:28:37]# sed 's/root/tankzhang/g' test |grep tankzhang
tankzhang:x:0:0:tankzhang:/tankzhang:/bin/bash
**示例3:**加了-n和p后表示只打印那些发生替换的行(部分替换),下面的例子,不需要使用grep命令
bash
[root@server ~ 14:23:12]# sed -n 's/root/tankzhang/p' test
tankzhang:x:0:0:root:/root:/bin/bash
**示例4:**加了-n和pg后表示只打印那些发生替换的行(全部替换)
bash
[root@server ~ 14:20:16]# cat test |sed -n 's/root/tankzhang/gp'
tankzhang:x:0:0:tankzhang:/tankzhang:/bin/bash
**示例5:**在第二行到第八行之间,替换以zhang开头的行,用ying来替换,并显示替换的行
bash
[root@server ~ 14:28:53]# sed -ne '2,8s/^zhang/ying/gp' test
yingy:x:1000:100:,,,:/home/zhangy:/bin/bash
示例6: 从以zhang开头的行开始,到匹配Po的行结束,在他们之间进行替换
bash
[root@server ~ 14:29:22]# sed -ne '/^zhang/,/Po/ s/zhang/ying/gp' test
yingy:x:1000:100:,,,:/home/yingy:/bin/bash
ba:x:1002:1002::/home/yingy:/bin/bash
@yingying:*:1004:1004::/home/test:/bin/bash
替换中的分隔符可以自定义,默认是/。
示例7: 自定义替换分隔符为 #。
bash
[root@server ~ 14:21:55]# ls -1 /etc/ho* | sed -n 's/c\/h/==/p'
/et==ost.conf
/et==ostname
/et==osts
/et==osts.allow
/et==osts.deny
[root@server ~ 14:22:41]# ls -1 /etc/ho* | sed -n 's#c/h#==#p'
/et==ost.conf
/et==ostname
/et==osts
/et==osts.allow
/et==osts.deny
分隔符 ; 和 -e 选项
需要执行多个sed处理命令 时,用分号分开 ,或者使用 -e 选项。
示例:
- 在第2行到第8行之间,替换以zhang开头的行,用ying来替换
- 在第5行到第10行之间,用goodbay来替换dbus,并显示替换的行
bash
插入
a 在匹配行下面插入新行
bash
[root@server ~ 14:31:50]# sed '/root/a====aaaa====' test
root:x:0:0:root:/root:/bin/bash
====aaaa====
i 在匹配行上面插入新行
bash
[root@server ~ 15:18:03]# sed -nr '/root/i====iiii====\nroot/p' test
====iiii====
root/p
删除
作用
- d,删除模式空间所有记录。
- D,删除模式空间第一行记录。
语法
d 格式:[address1[,address2]]d
D 格式:[address1[,address2]]D
address1和address2分别是 起始地址 和 结束地址 ,可以是 行号 或 模式字符串。address1和address2都是可选参数,可以都不填,这时候就是删除所有行,从文件的开头到文件结束。- 如果存在一个,那么就是删除 单行 。也就是只删除
address1指定的那行。 d命令仅从 模式缓冲区 中删除行,也就是该行不会发送到输出流,原始文件保持不变。
d 删除 示例
bash
# 删除1,14行
[root@server ~ 15:28:06]# sed -e '1,14d' test
[root@server ~ 16:14:39]# cat test
====iiii====
root/p
#删除4以后的行,包括第4行,把$当成最大行数就行了
[root@server ~ 18:35:26]# cat test |sed -e '4,$d'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
#删除包括false的行,或者包括bash的行,别忘了加\转义字符
[root@server ~ 18:37:50]# cat test |sed -e '/\(false\|bash\)/d'
policykit:x:102:1005:Po
#删除从匹配root的行,到匹配以test开头的行,中间的行
[root@server ~ 18:38:27]# cat test |sed -e '/root/,/^test/d'
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po
使用 s 命令实现删除
bash
#删除 test 文件中所有以 "root" 开头的行,同时删除文件中的所有空行
[root@server ~ 18:50:18]# cat test |sed -r 's/^root(.*)$//;/^$/d'
#删除特定字符串
[root@server ~ 18:50:27]# cat test |sed -nr 's/^root//gp'
:x:0:0:root:/root:/bin/bash
D 删除 示例
删除当前模式空间开端至\n的内容,放弃之后的命令,对剩余模式空间继续执行sed。
bash
[root@server ~ 18:52:46]# echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5' | sed 'N;D'
This is 5
说明:
- 读取
This is 1,执行N,得出This is 1\nThis is 2\n,执行D。 - 读取
This is 3,执行N,得出This is 3\nThis is 4\n,执行D。 - 读取
This is 5,执行N,后续无内容,读取失败,放弃后续命令,正常打印This is 5
删除偶数行
bash
[root@server ~ 18:53:55]# echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5' | sed 'n;D'
This is 1
This is 3
This is 5
说明:
- 读取
This is 1,执行n,This is 2\n覆盖This is 1\n,执行D删除This is 2\n,This is 1\n没有删除,正常打印This is 1。 - 读取
This is 3,执行n,This is 4\n覆盖This is 3\n,执行D删除This is 4\n,正常打印This is 3。 - 读取
This is 5,执行n,后续无内容,读取失败,放弃后续命令,正常打印This is 5
打印行号
=====
bash
[root@server ~ 18:55:12]# sed '=' test
1
root:x:0:0:root:/root:/bin/bash
2
......
#给 test 文件的每一行文本「添加行号」,行号和原文之间用冒号 : 分隔,最终输出 "行号:原文" 的格式
[root@server ~ 18:56:13]# sed '=' test|sed 'N;s/\n/:/'
1:root:x:0:0:root:/root:/bin/bash
......
大小写转换
y 字符
bash
# 将小写字母s和i转换成大写字母S和I
[root@server ~ 18:59:40]# echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5' | sed 'y/si/SI/'
ThIS IS 1
ThIS IS 2
ThIS IS 3
ThIS IS 4
ThIS IS 5
读取
bash
#在 test 文件中所有「以 root 开头的行」的后面,插入 test2 文件的全部内容
[root@server ~ 19:06:02]# sed '/^root/r test2' test
root:x:0:0:root:/root:/bin/bash
=============
-------------
+++++++++++++
写入
w 写入
将模式空间中记录写入到文件中。
bash
#将root开头的行,写入test3中
[root@server ~ 19:09:49]# sed '/^root/w test3' test
[root@server ~ 19:12:45]# cat test3
root:x:0:0:root:/root:/bin/bash
W 写入
将模式空间中第一条记录写入到文件中。
bash
[root@server ~ 19:14:44]# cat scripts
1{
N
w write.log
}
[root@server ~ 19:14:51]# sed -n -f scripts test
# 小写w写入包含模式中所有行
[root@server ~ 19:15:06]# cat write.log
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
# 大写W写入只包含模式中第一行
[root@server ~ 19:16:30]# cat scripts
1{
N
W write.log
}
[root@server ~ 19:16:37]# sed -n -f scripts test
[root@server ~ 19:16:41]# cat write.log
root:x:0:0:root:/root:/bin/bash
更改
整行替换。
bash
#root开头行替换出hello
[root@server ~ 19:16:47]# sed '/^root/chello' testhello
bin:x:1:1:bin:/bin:/bin/false
多命令执行 {} 和-f 选项
对匹配的内容执行多个命令。
bash
#打印前两行
[root@server ~ 19:17:57]# echo 'This is 1
> This is 2
> This is 3' | sed -n '1{N;p}'
This is 1
This is 2
#只处理 test 文件第 1-5 行, 替换并打印
[root@server ~ 19:18:55]# sed -n '1,5{s/^root/hello/;p}' test
hello:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
mail:x:8:12:mail:/var/spool/mail:/bin/false
ftp:x:14:11:ftp:/home/ftp:/bin/false
#多个命令写成脚本
[root@server ~ 19:14:44]# cat scripts
1{
N
w write.log
}
#执行脚本
[root@server ~ 19:14:51]# sed -n -f scripts test
退出
bash
#`2q`的意思是到第二行的时候,退出
[root@server ~ 19:20:14]# sed '2q' test
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
! 匹配取反
表示后面的命令作用于所有没有被选定的行。
bash
[root@server ~ 19:25:56]# sed -n '/^root/!p' test
bin:x:1:1:bin:/bin:/bin/false
.....
bash
#`h`的作用是将找到的行,放到一个缓存区,`G` 的作用是将缓存区中的内容放到最后一行
[root@server ~ 19:26:22]# sed -e '/root/h' -e '$G' test
root:x:0:0:root:/root:/bin/bash
.....
ba:x:1002:1002::/home/zhangy:/bin/bash
test:x:1003:1003::/home/test:/bin/bash
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po
root:x:0:0:root:/root:/bin/bash
#行替换,用匹配root的行,来替换匹配zhangy的行
[root@server ~ 19:26:22]# sed -e '/root/h' -e '$G' test
.....
.....
正则用法
- sed中正则表达式需要转移字符\,例如,用括号要加上
\,不然会报错。 - 使用
-r选项不需要转义字符。
bash
[root@server ~ 18:50:18]# cat test |sed -r 's/^root(.*)$//;/^$/d'
#或者
cat test |sed 's/^root\(.*\)$//;/^$/d'
- 子串使用
- (),用于匹配子串
- \N,N是个数字,代表前面匹配的第N个子串
- &,代表匹配的所有内容