sed
# sed
流编辑器,过滤和替换文本。
工作原理
sed 命令将当前处理的行读入模式空间进行处理,处理完把结果输出,并清空模式空间。然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行。还有一个空间叫保持空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出。这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据。
Usage
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
sed [选项] '地址 命令' file
1
2
2
选项
- -n 不打印模式空间
- -e 执行脚本、表达式来处理
- -f 执行动作从文件读取执行
- -i 修改原文件
- -r 使用扩展正则表达式
命令
- s/regexp/replacement/ 替换字符串
- p 打印当前模式空间
- P 打印模式空间的第一行
- d 删除模式空间,开始下一个循环
- D 删除模式空间的第一行,开始下一个循环
- = 打印当前行号
- a \text 当前行追加文本
- i \text 当前行上面插入文本
- c \text 所选行替换新文本
- q 立即退出 sed 脚本
- r 追加文本来自文件
- : label label 为 b 和 t 命令
- b label 分支到脚本中带有标签的位置,如果分支不存在则分支到脚本的末尾
- t label 如果 s///是一个成功的替换,才跳转到标签
- h H 复制/追加模式空间到保持空间
- g G 复制/追加保持空间到模式空间
- x 交换模式空间和保持空间内容
- l 打印模式空间的行,并显示控制字符$
- n N 读取/追加下一行输入到模式空间
- w filename 写入当前模式空间到文件
- ! 取反、否定
- & 引用已匹配字符串
地址
- first~step 步长,每 step 行,从第 first 开始
- $ 匹配最后一行
- /regexp/ 正则表达式匹配行
- number 只匹配指定行
- addr1,addr2 开始匹配 addr1 行开始,直接 addr2 行结束
- addr1,+N 从 addr1 行开始,向后的 N 行
- addr1,~N 从 addr1 行开始,到 N 行结束
借助以下文本内容作为示例讲解:
# tail /etc/services
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 1. 匹配打印 (p)
1)打印匹配 blp5 开头的行
# tail /etc/services |sed -n '/^blp5/p'
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
2)打印第一行
# tail /etc/services |sed -n '1p'
nimgtw 48003/udp # Nimbus Gateway
3)打印第一行至第三行
# tail /etc/services |sed -n '1,3p'
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
4)打印奇数行
# seq 10 |sed -n '1~2p'
1
3
5
7
9
5)打印匹配行及后一行
# tail /etc/services |sed -n '/blp5/,+1p'
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
6)打印最后一行
# tail /etc/services |sed -n '$p'
iqobject 48619/udp # iqobject
7)不打印最后一行
# tail /etc/services |sed -n '$!p'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
# 感叹号也就是对后面的命令取反。
8)匹配范围
# tail /etc/services |sed -n '/^blp5/,/^com/p'
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
#匹配开头行到最后一行:
# tail /etc/services |sed -n '/blp5/,$p'
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
#以逗号分开两个样式选择某个范围。
9)引用系统变量,用引号
# a=1
# tail /etc/services |sed -n ''$a',3p'
或
# tail /etc/services |sed -n "$a,3p"
# sed 命令用单引号时,里面变量用单引号引起来,或者 sed 命令用双引号,因为双引号解释特殊符号原有意义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 2. 匹配删除 (d)
删除与打印使用方法类似,简单举几个例子。
# tail /etc/services |sed '/blp5/d'
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
# tail /etc/services |sed '1d'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
# tail /etc/services |sed '1~2d'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/udp # iqobject
# tail /etc/services |sed '1,3d'
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
# 去除空格 http.conf 文件空行或开头#号的行:
# sed '/^#/d;/^$/d' /etc/httpd/conf/httpd.conf
# 打印是把匹配的打印出来,删除是把匹配的删除,删除只是不用-n 选项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 3. 替换 ( s/// )
1)替换 blp5 字符串为 test
# tail /etc/services |sed 's/blp5/test/'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
test 48129/tcp # Bloomberg locator
test 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
# 全局替换加 g:
# tail /etc/services |sed 's/blp5/test/g'
2)替换开头是 blp5 的字符串并打印
# tail /etc/services |sed -n 's/^blp5/test/p'
test 48129/tcp # Bloomberg locator
test 48129/udp # Bloomberg locator
3)使用&命令引用匹配内容并替换
# tail /etc/services |sed 's/48049/&.0/'
3gpp-cbsp 48049.0/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
# IP 加单引号:
# echo '10.10.10.1 10.10.10.2 10.10.10.3' |sed -r 's/[^ ]+/"&"/g'
"10.10.10.1" "10.10.10.2" "10.10.10.3"
4)对 1-4 行的 blp5 进行替换
# tail /etc/services | sed '1,4s/blp5/test/'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
test 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
5)对匹配行进行替换
# tail /etc/services | sed '/48129\/tcp/s/blp5/test/'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
test 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
6)二次匹配替换
# tail /etc/services |sed 's/blp5/test/;s/3g/4g/'
4gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
test 48129/tcp # Bloomberg locator
test 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
7)分组使用,在每个字符串后面添加 123
# tail /etc/services |sed -r 's/(.*) (.*)(#.*)/\1\2test \3/'
3gpp-cbsp 48049/tcp test # 3GPP Cell Broadcast Service
isnetserv 48128/tcp test # Image Systems Network Services
isnetserv 48128/udp test # Image Systems Network Services
blp5 48129/tcp test # Bloomberg locator
blp5 48129/udp test # Bloomberg locator
com-bardac-dw 48556/tcp test # com-bardac-dw
com-bardac-dw 48556/udp test # com-bardac-dw
iqobject 48619/tcp test # iqobject
iqobject 48619/udp test # iqobject
matahari 49000/tcp test # Matahari Broker
# 第一列是第一个小括号匹配,第二列第二个小括号匹配,第三列一样。将不变的字符串匹配分组,再通过\数字按分组顺序反向引用。
8)将协议与端口号位置调换
# tail /etc/services |sed -r 's/(.*)(\<[0-9]+\>)\/(tcp|udp)(.*)/\1\3\/\2\4/'
3gpp-cbsp tcp/48049 # 3GPP Cell Broadcast Service
isnetserv tcp/48128 # Image Systems Network Services
isnetserv udp/48128 # Image Systems Network Services
blp5 tcp/48129 # Bloomberg locator
blp5 udp/48129 # Bloomberg locator
com-bardac-dw tcp/48556 # com-bardac-dw
com-bardac-dw udp/48556 # com-bardac-dw
iqobject tcp/48619 # iqobject
iqobject udp/48619 # iqobject
matahari tcp/49000 # Matahari Broker
9)位置调换
# 替换 x 字符为大写:
# echo "abc cde xyz" |sed -r 's/(.*)x/\1X/'
abc cde Xyz
#456 与 cde 调换:
# echo "abc:cde;123:456" |sed -r 's/([^:]+)(;.*:)([^:]+$)/\3\2\1/'
abc:456;123:cde
10)注释匹配行后的多少行
# seq 10 |sed '/5/,+3s/^/#/'
1
2
3
4
#5
#6
#7
#8
9
10
11)注释指定多行
# seq 5 |sed -r 's/^3|^4/&#/'
1
2
3#
4#
5
# seq 5 |sed -r '/^3|^4/s/^/#/'
1
2
#3
#4
5
# seq 5 |sed -r 's/^3|^4/#\0/'
1
2
#3
#4
5
12)去除开头和结尾空格或制表符
# echo " 1 2 3 " |sed 's/^[ \t]*//;s/[ \t]*$//'
1 2 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# 4. 多重编辑(-e)
# tail /etc/services |sed -e '1,2d' -e 's/blp5/test/'
isnetserv 48128/udp # Image Systems Network Services
test 48129/tcp # Bloomberg locator
test 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
# 也可以使用分号分隔:
# tail /etc/services |sed '1,2d;s/blp5/test/'
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 5. 添加新内容(a、i 、c)
1)在 blp5 上一行添加 test
# tail /etc/services |sed '/blp5/i \test'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
test
blp5 48129/tcp # Bloomberg locator
test
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
2)在 blp5 下一行添加 test
# tail /etc/services |sed '/blp5/a \test'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
test
blp5 48129/udp # Bloomberg locator
test
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
3)将 blp5 替换新行
# tail /etc/services |sed '/blp5/c \test'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
test
test
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
4)在指定行下一行添加一行
# tail /etc/services |sed '2a \test'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
test
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
5)在指定行前面和后面添加一行
# seq 5 |sed '3s/.*/txt\n&/'
1
2
txt
3
4
5
# seq 5 |sed '3s/.*/&\ntxt/'
1
2
3
txt
4
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 6. 读取文件并追加到匹配行后 (r)
# cat a.txt
123
456
# tail /etc/services |sed '/blp5/r a.txt'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
123
456
blp5 48129/udp # Bloomberg locator
123
456
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 7. 将匹配行写到文件 (w)
# tail /etc/services |sed '/blp5/w b.txt'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker
# cat b.txt
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 8. 读取下一行(n 和 N )
n 读取下一行到模式空间。
N 追加下一行内容到模式空间,并以换行符\n 分隔。
1)打印匹配的下一行
# seq 5 |sed -n '/3/{n;p}'
4
2)打印偶数
# seq 6 |sed -n 'n;p'
2
4
6
# sed 先读取第一行 1,执行 n 命令,获取下一行 2,此时模式空间是 2,执行 p 命令,打印模式空间。 现在模式空间是 2,sed 再读取 3,执行 n 命令,获取下一行 4,此时模式空间为 4,执行 p 命令,以此类推。
3)打印奇数
# seq 6 |sed 'n;d'
1
3
5
# sed 先读取第一行 1,此时模式空间是 1,并打印模式空间 1,执行 n 命令,获取下一行 2,执行 d命令,删除模式空间的 2,sed 再读取 3,此时模式空间是 3,并打印模式空间,再执行 n 命令,获取下一行 4,执行 d 命令,删除模式空间的 3,以此类推。
# seq 6 |sed -n 'p;n'
1
3
5
4)每三行执行一次 p 命令
# seq 6 |sed 'n;n;p'
1
2
3
3
4
5
6
6
# sed 先读取第一行 1,并打印模式空间 1,执行 n 命令,获取下一行 2,并打印模式空间 2,再执行 n命令,获取下一行 3,执行 p 命令,打印模式空间 3。sed 读取下一行 3,并打印模式空间 3,以此类推。
5)每三行替换一次
方法 1:
# seq 6 |sed 'n;n;s/^/=/;s/$/=/'
1
2
=3=
4
5
=6=
我们只是把 p 命令改成了替换命令。
方法 2:
这次用到了地址匹配,来实现上面的效果:
# seq 6 |sed '3~3{s/^/=/;s/$/=/}'
1
2
=3=
4
5
=6=
当执行多个 sed 命令时,有时相互会产生影响,我们可以用大括号{}把他们括起来。
6)再看下 N 命令的功能
# seq 6 |sed 'N;q'
1
2
将两行合并一行:
# seq 6 |sed 'N;s/\n//'
12
34
56
第一个命令:sed 读取第一行 1,N 命令读取下一行 2,并以\n2 追加,此时模式空间是 1\n2,再执行 q 退出。为了进一步说明 N 的功能,看第二个命令:执行 N 命令后,此时模式空间是 1\n2,再执行把\n 替换为空,此时模式空间是 12,并打印。
# seq 5 |sed -n 'N;p'
1
2
3
4
# seq 6 |sed -n 'N;p'
1
2
3
4
5
6
为什么第一个不打印 5 呢?因为 N 命令是读取下一行追加到 sed 读取的当前行,当 N 读取下一行没有内容时,则退出,也不会执行 p 命令打印当前行。
当行数为偶数时,N 始终就能读到下一行,所以也会执行 p 命令。
7)打印奇数行数时的最后一行
# seq 5 |sed -n '$!N;p'
1
2
3
4
5
加一个满足条件,当 sed 执行到最后一行时,用感叹号不去执行 N 命令,随后执行 p 命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# 9. 打印和删除模式空间第一行(P 和 D)
P 打印模式空间的第一行。
D 删除模式空间的第一行。
1)打印奇数
# seq 6 |sed -n 'N;P'
1
3
5
2)保留最后一行
# seq 6 |sed 'N;D'
6
读取第一行 1,执行 N 命令读取下一行并追加到模式空间,此时模式空间是 1\n2,执行 D 命令删除模式空间第一行 1,剩余 2。
读取第二行,执行 N 命令,此时模式空间是 3\n4,执行 D 命令删除模式空间第一行 3,剩余 4。
以此类推,读取最后一行打印时,而 N 获取不到下一行则退出,不再执行 D,因此模式空间只剩余 6就打印。
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 10. 保持空间操作(h 与 H 、g 与 G 和 x )
h 复制模式空间内容到保持空间(覆盖)。
H 复制模式空间内容追加到保持空间。
g 复制保持空间内容到模式空间(覆盖)。
G 复制保持空间内容追加到模式空间。
x 模式空间与保持空间内容互换
1)将匹配的内容覆盖到另一个匹配
# seq 6 |sed -e '/3/{h;d}' -e '/5/g'
1
2
4
3
6
h 命令把匹配的 3 复制到保持空间,d 命令删除模式空间的 3。后面命令再对模式空间匹配 5,并用
g 命令把保持空间 3 覆盖模式空间 5。
2)将匹配的内容放到最后
# seq 6 |sed -e '/3/{h;d}' -e '$G'
1
2
4
5
6
3
3)交换模式空间和保持空间
# seq 6 |sed -e '/3/{h;d}' -e '/5/x' -e '$G'
1
2
4
3
6
5
看后面命令,在模式空间匹配 5 并将保持空间的 3 与 5 交换,5 就变成了 3,。最后把保持空间的 5 追加到模式空间的。
4)倒叙输出
# seq 5 |sed '1!G;h;$!d'
5
4
3
2
1
分析下:
1!G 第一行不执行把保持空间内容追加到模式空间,因为现在保持空间还没有数据。
h 将模式空间放到保持空间暂存。
$!d 最后一行不执行删除模式空间的内容。
读取第一行 1 时,跳过 G 命令,执行 h 命令将模式空间 1 复制到保持空间,执行 d 命令删除模式空间的 1。
读取第二行 2 时,模式空间是 2,执行 G 命令,将保持空间 1 追加到模式空间,此时模式空间是2\n1,执行 h 命令将 2\n1 覆盖到保持空间,d 删除模式空间。
读取第三行 3 时,模式空间是 3,执行 G 命令,将保持空间 2\n1 追加到模式空间,此时模式空间是3\n2\n1,执行 h 命令将模式空间内容复制到保持空间,d 删除模式空间。
以此类推,读到第 5 行时,模式空间是 5,执行 G 命令,将保持空间的 4\n3\n2\n1 追加模式空间,然后复制到模式空间,5\n4\n3\n2\n1,不执行 d,模式空间保留,输出。
由此可见,每次读取的行先放到模式空间,再复制到保持空间,d 命令删除模式空间内容,防止输出,再追加到模式空间,因为追加到模式空间,会追加到新读取的一行的后面,循环这样操作, 就把所有行一行行追加到新读取行的后面,就形成了倒叙。
5)每行后面添加新空行
# seq 10 |sed G
1
2
3
4
5
6)打印匹配行的上一行内容
# seq 5 |sed -n '/3/{x;p};h'
2
读取第一行 1,没有匹配到 3,不执行{x;p},执行 h 命令将模式空间内容 1 覆盖到保持空间。
读取第二行 2,没有匹配到 3,不执行{x;p},执行 h 命令将模式空间内容 2 覆盖到保持空间。
读取第三行 3,匹配到 3,执行 x 命令把模式空间 3 与保持空间 2 交换,再执行 p 打印模式空间 2.
以此类推。
7)打印匹配行到最后一行或下一行到最后一行
# seq 5 |sed -n '/3/,$p'
3
4
5
# seq 5 |sed -n '/3/,${h;x;p}'
3
4
5
# seq 5 |sed -n '/3/{:a;N;$!ba;p}'
3
4
5
# seq 5 |sed -n '/3/{n;:a;N;$!ba;p}'
4
5
匹配到 3 时,n 读取下一行 4,此时模式空间是 4,执行 N 命令读取下一行并追加到模式空间,此时模式空间是 4\n5,标签循环完成后打印模式空间 4\n5。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# 11. 标签 (: 、b 和 t )
标签可以控制流,实现分支判断。
- : lable name 定义标签
- b lable 跳转到指定标签,如果没有标签则到脚本末尾
- t lable 跳转到指定标签,前提是 s///命令执行成功
1)将换行符替换成逗号
方法 1:
# seq 6 |sed 'N;s/\n/,/'
1,2
3,4
5,6
这种方式并不能满足我们的需求,每次 sed 读取到模式空间再打印是新行,替换\n 也只能对 N 命令追加后的 1\n2 这样替换。这时就可以用到标签了:
# seq 6 |sed ':a;N;s/\n/,/;b a'
1,2,3,4,5,6
看看这里的标签使用,:a 是定义的标签名,b a 是跳转到 a 位置。
sed 读取第一行 1,N 命令读取下一行 2,此时模式空间是 1\n2$,执行替换,此时模式空间是1,2$,执行 b 命令再跳转到标签 a 位置继续执行 N 命令,读取下一行 3 追加到模式空间,此时模式空间是 1,2\n3$,再替换,以此类推,不断追加替换,直到最后一行 N 读不到下一行内容退出。
方法 2:
# seq 6 |sed ':a;N;$!b a;s/\n/,/g'
1,2,3,4,5,6
先将每行读入到模式空间,最后再执行全局替换。$!是如果是最后一行,则不执行 b a 跳转,最后执行全局替换。
# seq 6 |sed ':a;N;b a;s/\n/,/g'
1
2
3
4
5
6
可以看到,不加$!是没有替换,因为循环到 N 命令没有读到行就退出了,后面的替换也就没执行。
2)每三个数字加个一个逗号
# echo "123456789" |sed -r 's/([0-9]+)([0-9]+{3})/\1,\2/'
123456,789
# echo "123456789" |sed -r ':a;s/([0-9]+)([0-9]+{3})/\1,\2/;t a'
123,456,789
# echo "123456789" |sed -r ':a;s/([0-9]+)([0-9]+{2})/\1,\2/;t a'
1,23,45,67,89
执行第一次时,替换最后一个,跳转后,再对 123456 匹配替换,直到匹配替换不成功,不执行 t 命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 12. 忽略大小写匹配 (I)
# echo -e "a\nA\nb\nc" |sed 's/a/1/Ig'
1
1
b
c
1
2
3
4
5
2
3
4
5
# 13. 获取总行数 (#)
seq 10 |sed -n '$='
1
上次更新: 2022/11/06, 20:20:54