sed使用手册
文章目录
- sed使用手册
- sed 介绍
- sed 工作流程
- sed 注意事项
- sed 命令语法
- sed 帮助
- -e 选项
- -f 选项
- -n 选项
- sed 行寻址
- 作用
- 语法
- 示例文件
- 演示
- sed 模式寻址
- 示例文件
- 演示
- sed 子命令
- 打印
- 作用
- 语法
- 示例
- 读取下一行
- 替换
sed使用手册
sed 介绍
sed,英文全称 stream editor ,是一种非交互式的流编辑器,能够实现对文本非交互式的处理,功能很强大。
sed 是一个 70 后,诞生于 1973 - 1974 年间,具体时间未知。而出生地则是鼎鼎大名的 贝尔实验室。
sed 是 麦克马洪 ( McMahon ) 老爷子在 贝尔实验室 时开发出来的。
sed 的诞生使并不是那么的神秘,它的诞生只不过是 麦克马洪 ( McMahon ) 老爷子想写一个 行编辑器,谁知写着写着就写成了 sed 的样子。
其实,在 sed 之前还有一个更古老的行编辑器,名字叫做 ed 编辑器。大概是 麦克马洪 ( McMahon ) 老爷子觉得 ed 编辑器不好用吧,顺手重新构架和编写。
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 命令语法
sed 帮助
[root@server ~ 15:31:37]# sed --help
用法: sed [选项]... {脚本(如果没有其他脚本)} [输入文件]...-n, --quiet, --silent取消自动打印模式空间-e 脚本, --expression=脚本添加“脚本”到程序的运行列表-f 脚本文件, --file=脚本文件添加“脚本文件”到程序的运行列表--follow-symlinks直接修改文件时跟随软链接-i[SUFFIX], --in-place[=SUFFIX]edit files in place (makes backup if SUFFIX supplied)-c, --copyuse copy instead of rename when shuffling files in -i mode-b, --binarydoes nothing; for compatibility with WIN32/CYGWIN/MSDOS/EMX (open files in binary mode (CR+LFs are not treated specially))-l N, --line-length=N指定“l”命令的换行期望长度--posix关闭所有 GNU 扩展-r, --regexp-extended在脚本中使用扩展正则表达式-s, --separate将输入文件视为各个独立的文件而不是一个长的连续输入-u, --unbuffered从输入文件读取最少的数据,更频繁的刷新输出-z, --null-dataseparate lines by NUL characters--helpdisplay this help and exit--versionoutput version information and exit
[root@server ~ 15:33:34]# man sed
SED(1) User Commands SED(1)NAMEsed - stream editor for filtering and transformingtextSYNOPSISsed [OPTION]... {script-only-if-no-other-script}[input-file]...
总的来说 sed 命令主要由四部分构成:
sed
命令。[option]
命令行选项,用于改变 sed 的工作流程。[sed-command]
是具体的 sed 命令。[input-file]
输入数据,如果不指定,则默认从标准输入中读取。
示例1:模拟cat命令打印文件内容
[root@server ~ 15:34:19]# cat > data.txt <<'EOF'
> I am studing sed
> I am www.laoma.cloud
> I am a Superman
> I am so handsome
> EOF
[root@server ~ 15:36:58]# sed '' data.txt
I am studing sed
I am www.laoma.cloud
I am a Superman
I am so handsome
对照着 sed 命令的语法格式:
- 这里未使用
option
。 ''
,对应着[sed-command]
为具体的 sed 语句。data.txt
,对应着[input-file]
,用于提供输入数据。
示例2:从标准输入中读取数据
如果我们没有提供输入文件,那么 sed 默认会冲标准输入中读取数据。
[root@server ~ 15:37:09]# sed ''
# 输入hello world,并回车
hello world
# 输出hello world
hello world
# 按ctrl+d推出
-e 选项
从命令行读取sed命令,我们需要将 sed 命令使用单引号 ( ''
) 引起来。
# 打印data.txt文件内容
[root@server ~ 15:38:51]# sed -e '' data.txt
I am studing sed
I am www.laoma.cloud
I am a Superman
I am so handsome# 如果只有一个命令,-e选项可以省略
[root@server ~ 15:39:04]# sed '' data.txt
I am studing sed
I am www.laoma.cloud
I am a Superman
I am so handsome[root@server ~ 15:39:09]# sed -e '1d' -e '2d' -e '5d' data.txt
I am a Superman
I am so handsome
# 因为不存在第五行,所以也就没删除的效果# 使用分号(;)分开多个命令
[root@server ~ 15:39:42]# sed -e '1d;2d;5d' data.txt
I am a Superman
I am so handsome
-f 选项
sed 还支持把所有 sed 命令保存在一个普通的文本文件里,然后通过 -f
选项来运行这个文件。
当把 sed 存储在文件中时,需要注意 每一个 sed 命令独自成一行。
文件的作用仅仅用于存储命令而已,因此存储 sed 命令的文件并没有任何特殊,可以是一个 .txt
文本文件。
[root@server ~ 15:40:11]# echo -e "1d\n2d\n5d" > scripts
[root@server ~ 15:40:41]# cat scripts
1d
2d
5d
[root@server ~ 15:40:45]# sed -f scripts data.txt
I am a Superman
I am so handsome
-n 选项
如果指定了该选项,那么模式空间数据将不会自动打印,需要明确指明打印才会输出记录。
# 以下命令没有任何输出
[root@server ~ 15:40:50]# sed -n '' data.txt# 打印第一行记录
[root@server ~ 15:41:19]# sed -n '1p' data.txt
I am studing sed
sed 行寻址
作用
通过行寻址匹配要处理的输入流。
语法
这里以打印命令p为例。
语法:[address1[,address2]]p
address1
和address2
分别是 起始地址 和 结束地址,可以是 行号或 模式字符串。address1
和address2
都是可选参数,可以都不填,这时候就是打印所有行,从文件的开头到文件结束。- 如果存在一个,那么就是打印 单行。也就是只打印
address1
指定的那行。 p
命令仅从 模式缓冲区 中打印行,也就是该行不会发送到输出流,原始文件保持不变。
示例文件
[root@server ~ 13:51:17]# echo 'this is 1
> this is 2
> this is 3
> this is 4
> this is 5' >test
演示
示例1: 打印所有行
# 打印所有行
[root@server ~ 13:52:10]# cat test |sed ''
this is 1
this is 2
this is 3
this is 4
this is 5# sed 默认打印模式缓冲区中所有内容。# 等效于
[root@server ~ 13:52:19]# cat test |sed -n 'p'
this is 1
this is 2
this is 3
this is 4
this is 5
# -n 关闭sed打印模式缓冲区中所有内容。
# p命令,明确打印输出模式缓冲区中所有内容。
示例2: 打印特定行
# 打印第1行
[root@server ~ 13:52:40]# cat test |sed -n '1p'
this is 1# 打印第最后一行
[root@server ~ 13:52:47]# cat test |sed -n '$p'
this is 5
示例3: 打印第1行到3行
[root@server ~ 13:52:53]# cat test |sed -n '1,3p'
this is 1
this is 2
this is 3
示例4: 打印第3行到最后一行
[root@server ~ 13:53:01]# cat test |sed -n '3,$p'
this is 3
this is 4
this is 5
示例5: 连续输出,打印第2行以及后续两行
[root@server ~ 13:53:08]# cat test |sed -n '2,+2p'
this is 2
this is 3
this is 4
示例6: 隔行输出,打印第1行以及后续隔2行输出
[root@server ~ 13:53:20]# cat test |sed -n '1~2p'
this is 1
this is 3
this is 5
sed 模式寻址
sed 除了可以从行号来选择行,s还支持模式查找指定的行。
-
模式 可以是一个普通的字符串或者一个正则表达式。
-
模式 的语法和行寻址的语法类似,只是把行号换成了 模式 匹配。
例如,输出匹配指定模式的行,语法格式如下:
/pattern/
示例文件
[root@server ~ 13:53:31]# 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
演示
示例1: 打印含有字符串zhang的行
[root@server ~ 14:16:40]# cat test | sed -n '/zhang/p'
zhangy:x:1000:100:,,,:/home/zhangy:/bin/bash
ba:x:1002:1002::/home/zhangy:/bin/bash
@zhangying:*:1004:1004::/home/test:/bin/bash
示例2: 打印root开头的行到zhang开头的行
[root@server ~ 14:17:04]# cat test | sed -n '/^root/,/^mail/p'
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
示例3: 打印root开头的行到第三行
[root@server ~ 14:17:34]# cat test | sed -n '/^root/,3p'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
示例4: 打印root开头的行到最后一行
[root@server ~ 14:17:47]# cat test | sed -n '/^root/,$p'
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
sed 子命令
sed 命令需要关注的子命令:
- 查找替换 S
- 行上方插入新行 i(insert),特定字符串前面插入字符串或者行前,使用s替换
- 行下方插入新行 a(append),特定字符串后面插入字符串或者行尾,使用s替换
- 删除整行 d(delete),删除特定字符串,使用s替换
打印
作用
- p,打印模式空间所有记录。
- P,打印模式空间第一行记录。
语法
格式:[address1[,address2]]p
address1
和address2
分别是 起始地址 和 结束地址,可以是 行号或 模式字符串。address1
和address2
都是可选参数,可以都不填,这时候就是打印所有行,从文件的开头到文件结束。- 如果存在一个,那么就是打印 单行。也就是只打印
address1
指定的那行。 p
命令仅从 模式缓冲区 中打印行,也就是该行不会发送到输出流,原始文件保持不变。
示例
[root@server ~ 14:17:54]# echo 'This is 1
> This is 2
> This is 3' | sed -n '1{N;p}'
This is 1
This is 2
[root@server ~ 14:18:17]# echo 'This is 1
> This is 2
> This is 3' | sed -n '1{N;P}'
This is 1
读取下一行
- n,提前读取下一行,覆盖模型空间之前读取的行。模型空间之前读取的行并没有删除,依然打印至标准输出,除非使用-n选项指明不打印。
示例1:打印偶数行内容
[root@server ~ 14:18:28]# 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命令。
因此,最终打印出来的就是偶数行。
替换
**示例1:**把test文件中的root替换成tankzhang,只不过只替换一次即终止在这一行的操作,并转到下一行
[root@server ~ 14:18:40]# sed 's/root/tankzhang/' test |grep tankzhang
tankzhang:x:0:0:root:/root:/bin/bash
**示例2:**把test文件中的root全部替换成tankzhang。字母g是global的缩写。
[root@server ~ 14:19:54]# sed 's/root/tankzhang/g' test |grep tankzhang
tankzhang:x:0:0:tankzhang:/tankzhang:/bin/bash
**示例3:**加了-n
和p
后表示只打印那些发生替换的行(部分替换),下面的例子,不需要使用grep命令
[root@server ~ 14:20:43]# sed -n 's/root/tankzhang/p' test
tankzhang:x:0:0:root:/root:/bin/bash
**示例4:**加了-n
和pg
后表示只打印那些发生替换的行(全部替换)
root@server ~ 14:20:51]# sed -n 's/root/tankzhang/gp' test
tankzhang:x:0:0:tankzhang:/tankzhang:/bin/bash
**示例5:**在第二行到第八行之间,替换以zhang开头的行,用ying来替换,并显示替换的行
[root@server ~ 14:21:48]# sed -ne '2,8s/^zhang/ying/gp' test
yingy:x:1000:100:,,,:/home/zhangy:/bin/bash
替换中的分隔符可以自定义,默认是/。
示例6: 自定义替换分隔符为 #
。
[root@server ~ 14:28:35]# sed -n 's#root#hello#gp' test
hello:x:0:0:hello:/hello:/bin/bash
其他替换
[root@server ~ 14:29:08]# cat test | sed -nr 's/^root(.*)/root\1end line/p'
root:x:0:0:root:/root:/bin/bashend line[root@server ~ 14:31:00]# cat test | sed -nr 's/^root(.*)/root\1\nnew line/p'
root:x:0:0:root:/root:/bin/bash
new line#i-前面插入
[root@server ~ 14:32:36]# cat test | sed '/^root/ihello world'
hello world
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
... ...
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po#a-后行插入
[root@server ~ 14:32:42]# cat test | sed '/^root/ahello world'root:x:0:0:root:/root:/bin/bash
hello world
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
... ...
test:x:1003:1003::/home/test:/bin/bash
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po#删除root行
[root@server ~ 14:32:53]# cat test | sed '/^root/d'
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
... ...
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po#前面加入
[root@server ~ 14:33:03]# cat test | sed -r 's/^root/haharoot/'
haharoot:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/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[root@server ~ 14:33:30]# cat test | sed -nr 's/^root(.*)/haharoot\1/p'
haharoot:x:0:0:root:/root:/bin/bash#删除
[root@server ~ 14:33:49]# cat test | sed -r 's/^root(.*)//'bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
... ...
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po[root@server ~ 14:34:01]# cat test | sed -r 's/^root(.*)\n//p'
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
... ...
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po[root@server ~ 14:34:13]# cat test |sed -nr 's/^root(.*)/hhhroot\1/p'
hhhroot:x:0:0:root:/root:/bin/bash[root@server ~ 14:39:07]# cat test | sed -r 's/^root(.*)/hello\nroot\1/p'
hello
root:x:0:0:root:/root:/bin/bash
hello
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
... ...
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po[root@server ~ 14:39:19]# cat test | sed -r 's/^root(.*)/hello\nroot\1/'
hello
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
... ...
policykit:x:102:1005:Po[root@server ~ 14:39:49]# cat test | sed -nr 's/^root(.*)/hello\nroot\1/p'
hello
root:x:0:0:root:/root:/bin/bash