sed 使用手册

  • Linux 有三个处理文本的 “三剑客”,各有专长:

    • grep:擅长 “过滤” 文本(挑出符合条件的内容)

    • sed:擅长 “修改” 文本(替换、删除、添加内容等)

    • awk:擅长 “格式化” 输出(按规则拆分和重组内容)

    sed 和 awk 是文本处理的两大王牌,简单说:

    • sed 重点:替换文本内容

    • awk 重点:分割文本并重新组织

基础用法:打印文本

示例1:模拟cat命令打印文件内容

 # 创建测试文件
 [lyk@controller lab 10:17:53]$ touch data.txt
 [lyk@controller lab 10:18:12]$ vim data.txt 
 [lyk@controller lab 10:18:33]$ cat data.txt
 I am studing sed
 I am www.twle.cn
 I am a no-work-men
 I am so handsome
 ​
 # 用sed打印文件内容(''表示不做任何修改,直接输出)
 [lyk@controller lab 10:18:39]$ sed '' data.txt 
 I am studing sed
 I am www.twle.cn
 I am a no-work-men
 I am so handsome
 ​

示例2:从标准输入中读取数据

sed 也能直接处理键盘输入的内容:

 [lyk@controller lab 10:18:56]$ sed ''
 # 输入hello world,并回车
 hello world
 # 输出hello world
 hello world
 # 按ctrl+d推出

关键选项:-e、-f、-n

-e 选项:执行多个命令

从命令行读取sed命令,我们需要将 sed 命令使用单引号 ( '' ) 引起来。

 [lyk@controller lab 10:19:46]$ sed -e '' data.txt
 I am studing sed
 I am www.twle.cn
 I am a no-work-men
 I am so handsome
 ​
 ​
 [lyk@controller lab 10:20:49]$ sed '' data.txt 
 I am studing sed
 I am www.twle.cn
 I am a no-work-men
 I am so handsome
 ​
 # -e 选项可以多次使用,1d是作用是删除第一行
 [lyk@controller lab 10:20:59]$ sed -e '1d' -e '2d' -e '5d' data.txt
 I am a no-work-men
 I am so handsome
 # 不存在第五行,就没删除的效果
 ​
 # 使用分号(;)分开多个命令
 [lyk@controller lab 10:21:26]$ sed -e '1d;2d;5d' data.txt
 I am a no-work-men
 I am so handsome
-f 选项:从文件读取命令

如果命令太多,一行写不下,可以把命令存到一个文件里,用 -f 让 sed 读取执行

当把 sed 存储在文件中时,需要注意 每一个 sed 命令独自成一行

文件的作用仅仅用于存储命令而已,因此存储 sed 命令的文件并没有任何特殊,可以是一个 .txt 文本文件。

 # 把要执行的命令写到 scripts 文件(每行一个命令)
 [lyk@controller lab 10:22:47]$ echo -e "1d\n2d\n5d" > scripts
 [lyk@controller lab 10:23:25]$ cat scripts 
 1d
 2d
 5d
 # 用-f执行 scripts 里的命令
 [lyk@controller lab 10:23:31]$ sed -f scripts data.txt 
 I am a no-work-men
 I am so handsome

备注:适合命令复杂的场景,方便保存和复用

-n 选项:只输出指定内容

默认情况下,sed 会自动输出所有处理后的内容。-n 可以关闭这个 “自动输出”,只打印我们明确指定要输出的内容(配合 p 命令)

 # 加-n但不指定打印,结果无输出
 [lyk@controller lab 10:23:45]$ sed -n '' data.txt
 ​
 # 加-n和p命令:只打印第1行(p=打印)
 [lyk@controller lab 10:24:25]$ sed -n '1p' data.txt
 I am studing sed
 ​

备注-n + p 是 “精准输出” 的黄金搭档,想打印哪行就指定哪行

sed 行寻址:按行号定位内容

作用

通过行寻址匹配要处理的输入流。

  • 语法(以打印为例):

     [行号1[,行号2]]p
    • 只写一个行号:打印指定行

    • 行号 1, 行号 2:打印从行号 1 到行号 2 的所有行

    • $ 表示 “最后一行”

示例1

 # 先准备一个 test 文件,内容是5行
 [lyk@controller lab 10:24:29]$ echo 'This is 1    
 > This is 2    
 > This is 3
 > This is 4
 > This is 5 ' > test
 ​
 [lyk@controller lab 10:25:39]$ cat test | sed ''
 This is 1    
 This is 2    
 This is 3
 This is 4
 This is 5 
 ​
 #等同于
 [lyk@controller lab 10:26:05]$ 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行
 [lyk@controller lab 10:26:10]$ cat test | sed -n '1p'
 This is 1    
 ​
 # 打印最后一行
 [lyk@controller lab 10:26:53]$ cat test | sed -n '$p'
 This is 5 
 ​

示例3: 打印第1行到3行

[lyk@controller lab 10:27:45]$  cat test | sed -n '1,3p'
This is 1    
This is 2    
This is 3

示例4: 打印第3行到最后一行

[lyk@controller lab 10:27:49]$ cat test | sed -n '3,$p'
This is 3
This is 4
This is 5 

示例5: 连续输出,打印第2行以及后续两行

[lyk@controller lab 10:28:08]$ cat test | sed -n '2,+2p'
This is 2    
This is 3
This is 4

示例6: 隔行输出,打印第1行以及后续隔2行输出

[lyk@controller lab 10:28:25]$ cat test | sed -n '1~2p'
This is 1    
This is 3
This is 5 

sed 模式寻址:按内容定位行

除了行号,sed 还能按 “内容匹配” 定位行(支持字符串或正则表达式),就像按关键词找内容

语法:

/模式/p
  • 模式可以是普通字符串(如 zhang

  • 也可以是正则(如 ^root 表示以 root 开头)

示例文件(用 test 文件,内容是系统用户信息):
[lyk@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

示例1: 打印含有字符串zhang的行

[lyk@controller lab 10:29:54]$ 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
#返回根目录找test
[lyk@controller lab 10:35:39]$ cd
[lyk@controller ~ 10:36:01]$ 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开头的行

[lyk@controller ~ 10:36:20]$ 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开头的行到第三行

[lyk@controller ~ 10:37: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开头的行到最后一行

[lyk@controller ~ 10:37:48]$  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 子命令

  • 打印:p 和 P
    • p:打印模式空间里的所有内容(可以是一行或多行)

    • P:只打印模式空间里的第一行

# 示例:用N把两行合并到模式空间,p打印全部,P只打印第一行
[lyk@controller web 10:39:22]$ echo 'This is 1    
> This is 2    
> This is 3' | sed -n '1{N;p}'   # N=把下一行加到当前行后面

#输出
This is 1    
This is 2     # p打印合并后的两行


[lyk@controller web 10:39:32]$ echo 'This is 1    
> This is 2    
> This is 3' | sed -n '1{N;P}'

#输出
This is 1   
读取下一行
  • n:读取下一行,覆盖当前行(当前行会自动输出,除非用 -n)

  • N:读取下一行,追加到当前行后面(两行合并成一行处理,中间有换行符)

示例1:打印偶数行内容

[lyk@controller web 10:39:52]$ echo 'This is 1
> This is 2
> This is 3
> This is 4
> This is 5' | sed -n 'n;p'  # n=跳过当前行,p=打印下一行

#输出
This is 2
This is 4

原理:先读第 1 行,n 跳到第 2 行,p 打印;再读第 3 行,n 跳到第 4 行,p 打印...

用 N 合并行

示例1: 成对合并行

[lyk@controller web 10:41:25]$ cd

# 把相邻两行用 == 连接(N合并两行,s替换换行符)
[lyk@controller ~ 10:41:29]$ cat test | sed 'N;s/\n/==/'
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/ma
......

说明:

  1. N,追加下一行到当前行后面,组成一个新行来处理。

  2. s/\n/==/,将新行中 \n 换行符替换成==,末尾的换行符不替换

示例2: 打印前2行

[lyk@controller ~ 10:41:31]$  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   

替换:s / 旧内容 / 新内容 /

常用选项:
  • 不加选项:只替换每行中第一个匹配的内容

  • g:全局替换(替换一行中所有匹配的内容)

  • 配合 -np:只打印发生替换的行

示例1:把test文件中的root替换成tankzhang,只不过只替换一次即终止在这一行的操作,并转到下一行

[lyk@controller ~ 10:42:14]$ sed 's/root/tankzhang/' test|grep tankzhang
tankzhang:x:0:0:root:/root:/bin/bash

示例2:把test文件中的root全部替换成tankzhang。字母g是global的缩写

[lyk@controller ~ 10:42:48]$ sed 's/root/tankzhang/g' test |grep tankzhang
tankzhang:x:0:0:tankzhang:/tankzhang:/bin/bash

示例3:加了-np后表示只打印那些发生替换的行(部分替换),下面的例子,不需要使用grep命令

[lyk@controller ~ 10:43:07]$ sed -n 's/root/tankzhang/p' test
tankzhang:x:0:0:root:/root:/bin/bash

示例4:加了-npg后表示只打印那些发生替换的行(全部替换)

[lyk@controller ~ 10:43:23]$ sed -n 's/root/tankzhang/gp' test
tankzhang:x:0:0:tankzhang:/tankzhang:/bin/bash

示例5:在第二行到第八行之间,替换以zhang开头的行,用ying来替换,并显示替换的行

[lyk@controller ~ 10:43:37]$ sed -ne '2,8s/^zhang/ying/gp' test
yingy:x:1000:100:,,,:/home/zhangy:/bin/bash

示例6: 从以zhang开头的行开始,到匹配Po的行结束,在他们之间进行替换

[lyk@controller ~ 10:43:51]$ 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: 自定义替换分隔符为 #

[lyk@controller ~ 10:44:07]$ sed -n 's#root#hello#gp' test
hello:x:0:0:hello:/hello:/bin/bash

分隔符;和-e选项

需要执行多个sed处理命令时,用分号分开,或者使用 -e 选项。

示例:

  • 在第2行到第8行之间,替换以zhang开头的行,用ying来替换

  • 在第5行到第10行之间,用goodbay来替换dbus,并显示替换的行

[lyk@controller ~ 10:44:48]$ cat test | sed -n '2,8s/^zhang/ying/gp;5,10s#dbus#goodbay#gp'
yingy:x:1000:100:,,,:/home/zhangy:/bin/bash
goodbay:x:81:81:System message bus:/:/bin/false


[lyk@controller ~ 10:47:50]$ cat test | sed -ne '2,8s/zhang/ying/gp' -ne '5,10s#dbus#goodbay#gp'
yingy:x:1000:100:,,,:/home/yingy:/bin/bash
goodbay:x:81:81:System message bus:/:/bin/false

插入

a 在匹配行下面插入新行

将要插入的东西,插入到匹配行的下面

[lyk@controller ~ 10:48:25]$ sed '/root/a====aaaa====' test
root:x:0:0:root:/root:/bin/bash
====aaaa====
bin:x:1:1:bin:/bin:/bin/false
......
i 在匹配行上面插入新行

将要插入的东西,插入到匹配行的上面

[lyk@controller ~ 10:48:31]$ sed '/root/i====iiii====' test
====iiii====
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
......

删除

  • d:删除匹配到的所有行

  • D:只删除匹配到的行中的第一行(适用于合并后的多行)

d 删除

示例1: 删除1,14行

[lyk@controller ~ 10:49:03]$ sed -e '1,14d' test
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po

示例2: 删除4以后的行,包括第4行,把$当成最大行数就行了

[lyk@controller ~ 10:49:45]$ sed -e '4,$d' 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

示例3: 删除包括false的行,或者包括bash的行,别忘了加\

[lyk@controller ~ 10:50:09]$ sed -e '/\(false\|bash\)/d' test
policykit:x:102:1005:Po

示例4: 删除从匹配root的行,到匹配以test开头的行,中间的行

[lyk@controller ~ 10:50:24]$ sed -e '/root/,/^test/d' test
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit:x:102:1005:Po
D 删除 示例

删除当前模式空间开端至\n的内容,放弃之后的命令,对剩余模式空间继续执行sed。

示例1:读取最后一行内容

[lyk@controller web 10:51:09]$ 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

示例2:删除偶数行

[lyk@controller web 10:51:12]$ 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

其他实用命令

打印行号 =

示例1:

# 先打印行号,再打印内容(= 输出行号)
[lyk@controller ~ 10:53:08]$ sed '=' test
1
root:x:0:0:root:/root:/bin/bash
2
bin:x:1:1:bin:/bin:/bin/false
3
daemon:x:2:2:daemon:/sbin:/bin/false
......


[lyk@controller ~ 10:53:10]$ sed '=' test| sed 'N;s/\n/:/'
1:root:x:0:0:root:/root:/bin/bash
2:bin:x:1:1:bin:/bin:/bin/false
3:daemon:x:2:2:daemon:/sbin:/bin/false
4:mail:x:8:12:mail:/var/spool/mail:/bin/false
5:ftp:x:14:11:ftp:/home/ftp:/bin/false
......

大小写转换:y / 原字符 / 目标字符 /

[lyk@controller web 10:54:27]$ 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

读取

读写文件:r 和 w
  • r 文件名:把 “文件名” 中的内容读到匹配行的下面

  • w 文件名:把匹配到的内容写入 “文件名” 中

示例: 读取test2的内容,并将其写入到匹配行的下面

[lyk@controller ~ 10:55:12]$ vim test2
=============
-------------
+++++++++++++
[lyk@controller ~ 10:56:02]$ sed -e '/^root/r test2' 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
......

写入

w 写入

将模式空间中记录写入到文件中。

示例1: 将root开头的行,写入test3中

[lyk@controller ~ 10:56:20]$ sed -n '/^root/w test3' test
[lyk@controller ~ 10:56:56]$ cat test3
root:x:0:0:root:/root:/bin/bash
W 写入

将模式空间中第一条记录写入到文件中。

示例: 写入记录

# 小写w写入
[lyk@controller ~ 10:56:58]$ vim scripts 
1{
N
w write.log
}
[lyk@controller ~ 10:57:30]$ sed -n -f scripts test

# 小写w写入包含模式中所有行
[lyk@controller ~ 10:57:36]$ cat write.log
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false

# 大写W写入只包含模式中第一行
[lyk@controller ~ 10:58:00]$ vim scripts 
1{
N
W write.log
}
[lyk@controller ~ 10:58:11]$ sed -n -f scripts test
[lyk@controller ~ 10:58:20]$ cat write.log
root:x:0:0:root:/root:/bin/bash

更改

整行替换

示例:root开头行替换出hello

[lyk@controller ~ 10:57:45]$ sed '/^root/chello' test
hello
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
......

# 等同以下命令
[lyk@controller ~ 10:59:49]$  sed 's/^root.*/hello/' test
hello
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
......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值