Linux常用命令-sed

命令

sed

描述

stream editor for filtering and transforming text
文本处理工具

用法

1
2
sed [OPTION]... 'command' [file]...
sed [OPTION]... -f scriptfile [file]...

选项

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
Options:
-n 只显示经过sed处理后的行
-e 用于多个条件处理,顺序执行,即一次读取,多次处理
-f 从文件中读取处理命令
-i 直接更改文件,如果加后缀则先重命名原文件再创建一个新文件
-c 需配合-i加后缀使用,处理前先复制一份原文件到备份文件,然后直接修改原文件
-r 使用扩展正则,支持分组引用,最多支持引用9组\1到\9
-s 如果指定了多个文件,则分别处理每个文件而非合并后再处理
-u 不缓存数据
-z 不换行输出
--follow-symlinks 跟随链接跳转

地址:
N 匹配指定行
$ 匹配最后一行
N~step 匹配指定行并以step为步进,如1~2表示奇数行,2~2表示偶数行
/regexp/ 正则匹配,添加i或I表示忽略大小写匹配/xxx/i,遇到包含路径的字符/时需要转义为\/
\@regexp@ 正则匹配,使用这种方式,无需转义路径,@可以替换为任意字符
/regexp/,/regexp/ 正则范围匹配
N,/regexp/ 指定行到正则匹配行
/regexp/,$ 正则匹配行到文件末尾(即最后一行)
N,M 匹配N到M行
N,+M 匹配N到N+M行

命令:
a\ 追加内容到匹配行的下一行,最后的\可以省略,支持使用\n追加多行
i\ 追加内容到匹配行的上一行,同上
c\ 改写匹配行,同上
d 删除匹配行
q 退出sed脚本,可以指定退出代码
r 读取指定文件中的内容追加到当前输出
R 按行读取并追加
h 复制模式空间中的内容到内存缓冲区
H 追加模式空间中的内容到内存缓冲区
g 复制内存缓冲区的内容到模式空间
G 追加内存缓冲区的内容到模式空间
l 显示不可打印字符
n 读取匹配行的下一行复制到模式空间
N 读取匹配行的下一行追加到模式空间
p 显示匹配行
s/regexp/string/g 正则匹配并替换,可使用&来代指匹配到的内容,加g表示全部替换,加i或I表示忽略大小写,支持使用其他分隔符如@,#
w 保存匹配到的行到指定文件
y 字符替换
= 显示匹配行号
! 命令取反,如!p即显示不匹配的行
{} 匹配后如需执行多次处理需用{}括起来,如'/word/{s//& (world) /;s/^/+ /}'

正则表达式元字符,和grep命令的正则语法一致
^ 匹配行首,如^abc匹配所有以abc开头的行
$ 匹配行尾,如abc$匹配所有以abc结尾的行
^$ 匹配空行
^[[:space:]]*$ 匹配空白行,包括空格或tab所占的行
. 匹配除换行符(\n,\r)之外的任意单个字符,如a.c匹配abc,a2c等
* 匹配零个或多个先前字符,即匹配次数>=0次,如a*c匹配ac,aac,aaac等
.* 匹配任意长度的任意字符,如a.*c匹配ac,abc,aabbcc等
? 匹配零个或一个先前的字符,即匹配次数<=1次,如a?c匹配c,ac
+ 匹配一个或多个先前的字符,即匹配次数>=1次,如a+c匹配ac,aac,aaac等
| 或匹配,如a|b|c匹配a或b或c
() 分组,如abc([1-9])?匹配abc,abc1,abc123
[] 匹配指定范围内的任意单个字符,如[Aa]bc匹配Abc,abc
[^] 取反,匹配指定范围之外的任意单个字符,如[^Aa]bc匹配除了Abc和abc之外
\ 转义符,如\$匹配$本身
\< 匹配单词词首,如\<abc匹配以abc开头的单词
\> 匹配单词词尾,如abc\>匹配以abc结尾的单词
{n} 匹配n次,如a{2}匹配aa
{n,} 至少匹配n次,即>=n次,如a{2,}匹配aa,aaa等
{n,m} 匹配n-m次,包括n次和m次,即[n-m]次,其中n<=m,如a{2,4}匹配aa,aaa,aaaa
{,m} 最多匹配m次,即<=m次,如ab{,2}匹配a,ab,abb
\b 匹配单词边界,如\broot\b匹配单词root
\B 匹配非单词边界,如root\B匹配rooter而不匹配root
\w 匹配字母,数字和下划线,等同于[A-Za-z0-9_]
\W 匹配非\w的字符
\s 匹配空白字符

注意

补充

sed是一种流编辑器,读取一行,处理一行,输出一行.sed先读取文件中的一行内容存储到被称为模式空间(pattern space)的临时缓冲区中,接着根据设定的条件来处理缓冲区中的内容,多个条件则多次处理,处理完成后输出到屏幕,接着读取和处理下一行,直到文件末尾.原文件内容并没有改变,除非使用重定向存储输出.sed主要用来自动编辑一个或多个文件;简化对多个文件执行相同的编辑处理工作;编写转换程序.

sed处理的是缓冲区的数据,不影响原数据,一次读取,可以多次处理,后续的编辑命令都是应用前面命令编辑后输出的结果,所以一定要注意编辑命令的顺序问题.sed的处理顺序,先读取文件中的一行数据保存到缓冲区,再查看地址位置是否匹配,匹配则执行编辑命令,不匹配则继续查看下一个地址位置或继续读取下一行.

参考网址:https://kodango.com/article-series

示例

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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# sed多条件的处理流程
$ more f1
a
b
c
d
$ sed -n -e '1,3p' -e '2a111' -e '2d' f1
a
b
111
c
# 处理流程:
# 1.读取第一行,匹配第一个条件,打印输出,不匹配后两个条件,则第一行处理结束
# 2.读取第二行,匹配第一个条件,打印输出,匹配第二个条件,即在匹配行的下一行添加111,继续匹配第三个# 条件,删除第二行数据,注意这里删除的是缓冲区中的数据
# 3.读取第三行,匹配第一个条件,打印输出,不匹配后两个条件,则第三行处理结束

$ sed -n -e '2d' -e '1,3p' -e '2abc' f1
a
c
# 处理流程:
# 1.读取第一行,不匹配第一个条件,不处理,匹配第二个条件,打印输出,不匹配第三个条件,不处理,第一行处理结束
# 2.读取第二行,匹配第一个条件,删除处理,匹配后续两个条件,但缓冲区内容已被删除,所以输出为空,即最后不显示第二行内容
# 3.读取第三行,只匹配第二个条件,打印输出,第三行处理结束

$ more a
aaa
abc
aa bb cc
123
12345
a b c
bbb
ccc
# -n只显示匹配的行
$ sed -n '/aaa/p' a
aaa
# -e多个条件匹配和处理
$ sed -ne '/aaa/p' -ne '1abbb' a
aaa
bbb
# 遇到包含路径的字符/需要转义\/,或者使用其他字符代替,只需转义第一个代替的字符,如下的\@或\#
$ sed -n '/ /data /p' /etc/fstab
sed: -e expression #1, char 5: extra characters after command
$ sed -n '/ \/data /p' /etc/fstab
UUID=05c75b90-d3ef-419a-8a17-aa6340a18f29 /data ext4 defaults 0 0
$ sed -n '\@ /data @p' /etc/fstab
UUID=05c75b90-d3ef-419a-8a17-aa6340a18f29 /data ext4 defaults 0 0
$ sed -n '\# /data #p' /etc/fstab
# 查看文件的inode值
$ ls -il a
33602001 -rw-r--r-- 1 root root 41 Feb 28 15:04 a
# -i不加后缀则表示直接修改文件
$ sed -i '1abbb' a
# -i.bak表示先备份文件加后缀.bak,然后修改原文件
$ sed -i.bak '1abbb' a
# 通过inode可以看到-i.bak处理后是先重命名原文件为.bak,然后新建一个文件a处理
$ ls -il a*
33575026 -rw-r--r-- 1 root root 45 Feb 28 15:06 a
33602001 -rw-r--r-- 1 root root 41 Feb 28 15:04 a.bak
# 原文件a多了一行内容bbb
$ diff a a.bak
2d1
< bbb
$ rm a
$ mv a.bak a
$ ll -il a*
33602001 -rw-r--r-- 1 root root 41 Feb 28 15:04 a
# -ci.bak是复制原文件为.bak文件,然后直接编辑原文件
$ sed -ci.bak '1abbb' a
$ ll -il a*
33602001 -rw-r--r-- 1 root root 45 Feb 28 15:07 a
33601994 -rw-r--r-- 1 root root 41 Feb 28 15:07 a.bak
$ diff a a.bak
2d1
< bbb
$ more b
aaa
123
abccc
# 默认指定了多个文件,则自动合并文件内容后再处理
$ sed '1a111' a b
aaa
111
abc
...
aaa
123
abccc
# -s则分别处理每个文件,如下所有文件a和b均增加了一行111的内容
$ sed -s '1a111' a b
aaa
111
abc
...
aaa
111
123
abccc

# 编辑命令a追加到下一行,i追加到上一行
$ sed '1a111' a
aaa
111
abc
$ sed '1i111' a
111
aaa
abc
# q指定退出代码,显示前3行内容并退出,指定退出码为3
$ sed '3q3' a
aaa
abc
aa bb cc
$ echo $?
3
$ more aa
11
12
13
$ more bb
21
22
23
# r读取文件bb的第1行然后追加文件aa的所有内容,再读取第2行然后继续追加文件aa的内容
$ sed 'raa' bb
21
11
12
13
22
11
12
13
23
11
12
13
# 1r读取文件bb的第1行然后追加文件aa的所有内容
$ sed '1raa' bb
21
11
12
13
22
23
# R读取一行追加一行
$ sed 'Raa' bb
21
11
22
12
23
13
# c改写匹配行
$ sed '1cbbb' a
bbb
abc
aa bb cc
# d删除匹配行
$ sed '1d' a
abc
aa bb cc
$ sed '$d' a
$ sed '5,$d' a
# l显示不可打印字符
$ sed -n 'l' a
aaa$
abc$
aa bb cc$
123$
12345$
a b c$
bbb$
ccc$
# p显示匹配行
$ sed -n '1,3p' a
aaa
abc
aa bb cc
# s匹配aaa并再其后追加bbb
$ sed 's/aaa/&bbb/' a
aaabbb
abc
aa bb cc
$ sed -n '/[0-9]/p' a |sed -r 's/[0-9]+/&.&/'
123.123
12345.12345
# 也支持使用\1分组匹配引用
$ sed -n '/[0-9]/p' a |sed -r 's/([0-9]+)/&.\1/'
123.123
12345.12345
# w保存匹配行到文件b
$ sed -n '/aaa/wb' a
$ more b
aaa
# y将字符a替换为x
$ sed 'y/a/x/' a
xxx
xbc
xx bb cc
# =显示匹配的行号
$ sed -n '/aaa/=' a
1
7
# !p显示不匹配的行
$ sed -n '/aaa/!p' a
abc
aa bb cc
123
12345
a b c
bbb
ccc
# 正则匹配范围,显示从匹配aaa的行到匹配bbb的行
$ sed -n '/aaa/,/bbb/p' a
aaa
abc
aa bb cc
123
12345
a b c
aaa aaa aaa
bbb
# 指定行到正则匹配行,显示从第5行到匹配bbb的行
$ sed -n '5,/bbb/p' a
12345
a b c
aaa aaa aaa
bbb
# 匹配后执行多个处理条件用{}括起来
$ nl a |sed -n '/aa/{s/bb/22/;p}'
1 aaa
3 aa 22 cc
7 aaa aaa aaa
# 2~2从第2行开始匹配,并以2为步进匹配
$ seq 1 10 > aa
$ sed -n '2~2p' aa
2
4
6
8
10
# 匹配第3行到第6行
$ sed -n '3,+3p' aa
3
4
5
6
# 显示奇数行,2种方式
$ sed -n '1~2p' aa
$ sed -n 'p;n' aa
1
3
5
7
9
# 显示偶数行,2种方式
$ sed -n '2~2p' aa
$ sed -n 'n;p' aa
2
4
6
8
10
# 倒叙显示文件内容
$ sed '1!G;h;$!d' aa
10
9
8
7
6
5
4
3
2
1
# 匹配2个字符的单词,也包括数字
$ sed -n '/\b\w\{2\}\b/p' a
aa bb cc
11
# 匹配3个字符的单词,注意匹配的是行
$ sed -n '/\b\w\{3\}\b/p' a
aaa
abc
123
aaa aaa aaa
bbb
ccc
# 默认匹配大小写
$ cat file
aaaa
aaAA
AA BB
aAAa
aa bb
$ sed -n '/aa/p' file
aaaa
aaAA
aa bb
$ sed -n '/AA/p' file
aaAA
AA BB
aAAa
# 添加i或I,如/xxx/i可以忽略大小写匹配
$ sed -n '/\<aa\>/ip' file
$ sed -n '/\<aa\>/Ip' file
AA BB
aa bb
# 单词匹配可以使用\<xxx\>或\bxxx\b
$ sed -n '/\<AA\>/p' file
AA BB
$ sed -n '/\bAA\b/p' file
AA BB
$ sed -n '/\baa\b/p' file
aa bb
# 忽略大小写匹配单词
$ sed -n '/\baa\b/Ip' file
AA BB
aa bb
# 支持匹配多个单词
$ sed -n '/\baa bb\b/p' file
aa bb
# 显示空行行号,但是不包括空格行和tab空行,!=显示非空行号
$ sed -n '/^$/=' f1
# 显示非空行内容
$ sed -n '/^$/!p' f1
# 注释非空行
$ sed 's/[^$]/# &/' f1
# 删除空行
$ sed '/^$/d' f1
# 显示空行行号,包括空格行和tab行
$ sed -n '/^[[:space:]]*$/=' f1
# 删除空白行和#开头的行
$ sed '/^#/d;/^[[:space:]]*$/d' f1
# 删除每一行开头的空白(空格和tab),即左对齐排列全文
$ sed 's/^[ \t]*//' f1
# 删除每一行最后的空白(空格和tab)
$ sed 's/[ \t]*$//' f1
# 删除行尾的逗号,
$ sed 's/,$//' file > file.nocomma
# 删除行尾的最后一个字符,此为通用命令,如删除最后两个字符's/..$//'
$ sed 's/.$//' file > file.nolast
# 在a后面增加b,同时在被修改的行前面增加+号
$ sed '/a/{s//&b/;s/^/+ /}' f1
# 匹配word,在其后添加 (world) ,同时在行首添加+ 号
$ sed '/word/{s//& (world) /;s/^/+ /}' f1
# -e可以省略,可简写为第2条命令
$ sed -e '1,3p' -e '2d' f1
$ sed '1,3p;2d' f1
# 统计行数,相当于wc -l
$ sed -n '$=' f1
# 显示文件内容,相当于cat
$ sed '' f1
# 清空文件内容
$ sed -ni '' f1
# 清空前先复制文件到xxx.bak备份文件
$ sed -cni.bak '' f1
# 查找匹配的行
sed -n '/192.*centos/p' f1
# 注释匹配的行
sed -i '/192.*centos/s/^/#/' f1
# 取消注释匹配的行
sed -i '/192.*centos/s/#//' f1
# 全局替换
$ echo aaaaaa | sed 's/a/A/g'
AAAAAA
# 只替换第二个匹配项
$ echo aaaaaa | sed 's/a/A/2'
aAaaaa
# 从第二个匹配项开始替换到最后
$ echo aaaaaa | sed 's/a/A/2g'
aAAAAA
# 正则表达式\w\+表示匹配每一个单词,&表示引用匹配到单词
$ echo "this is a test line" | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]
# 将数字用逗号分隔
$ echo 12345678 |sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
12,345,678
# 日期格式转换
echo "2018/12/31" | sed 's#/#-#g'
# 注意b*匹配零个或多个b,有三个字符abc被替换成了1a,1,c1
$ echo abc | sed 's/b*/1/g'
1a1c1
# 取文件名,但是推荐使用basename命令
$ echo "/etc/sysconfig/network-scripts/ifcfg-eth0" |sed -r 's@(^/.*/)([^/]+/?)@\2@'
$ basename /etc/sysconfig/network-scripts/ifcfg-eth0
# 取目录名,但是推荐使用dirname命令
$ echo "/etc/sysconfig/network-scripts/ifcfg-eth0" |sed -r 's@(^/.*/)([^/]+/?)@\1@'
$ dirname /etc/sysconfig/network-scripts/ifcfg-eth0

# 分组引用和忽略大小写匹配替换
$ cat file
http://www.a.com/a/b/c/d-ef/wef/aaa.jpeg
https://www.aaa.com/a/xxb/eec/d-ef/wf/bbb.jpg
http://www.b.com/a/b/c/d-ef/wef/cca.png
https://img.aa.com/a/xxb/eec/bb.jpeg
http://image.aaa.com/a/xxb/eec/d-ef/dd.jpg
aa,http://img.aa.com/a/xxb/eec/bb.JPEG
# 匹配http或https替换为https,匹配.jpeg结尾替换为.jpg,url中间内容保持不变,匹配忽略大小写,且为全局匹配
$ sed -rn 's@(https?)(.*)(.jpeg$)@https\2.jpg@igp' file
https://www.a.com/a/b/c/d-ef/wef/aaa.jpg
https://img.aa.com/a/xxb/eec/bb.jpg
aa,https://img.aa.com/a/xxb/eec/bb.jpg
# 替换后的结果如下
$ sed -r 's@(https?)(.*)(.jpeg$)@https\2.jpg@ig' file
https://www.a.com/a/b/c/d-ef/wef/aaa.jpg
https://www.aaa.com/a/xxb/eec/d-ef/wf/bbb.jpg
http://www.b.com/a/b/c/d-ef/wef/cca.png
https://img.aa.com/a/xxb/eec/bb.jpg
http://image.aaa.com/a/xxb/eec/d-ef/dd.jpg
aa,https://img.aa.com/a/xxb/eec/bb.jpg

# 转换DOS的换行符(CR/LF)为Unix格式
$ file a.txt
a.txt: ASCII text, with CRLF line terminators
# windows文件中显示^M
$ cat -A a.txt
a^M$
b^M$
c^M$
# 以下两个命令均可以转换
$ sed 's/.$//' a.txt
$ sed 's/\x0D$//' a.txt
# 转换Unix的换行符(LF)为DOS格式
# unix文件中只显示$
$ cat -A a
aaa$
abc$
aa bb cc$
# 使用以下命令转换
$ sed 's/$/\r/' a

# 匹配以Host 开头的行到文件末尾(最后一行)之间的内容,删除包括Ciphers 的行,注意处理命令需要使用{}括起来,用于区分过滤命令和处理命令
sed -i '/^Host /,${/.*Ciphers /d}' /etc/ssh/ssh_config

# 先删除注释行和配置行,然后新增配置行到文件末尾,注意关键字的匹配,建议先通过grep命令筛查,避免误删除
# 推荐在脚本中使用如下两条命令的格式来修改配置文件,可以重复执行,实现幂等
sed -i '/.*Port /d' /etc/ssh/sshd_config
echo 'Port 22' >> /etc/ssh/sshd_config

# 引号原则: 显示引号需要加\转义,转义后的引号不能影响成组的引号,如果影响需要使用一组单引号括起来
# 显示双引号"
# 引号说明: 最外侧的两个单引号表示awk语句,里面的一组双引号表示print语句,中间的一个双引号为想要显示的内容,但是双引号需要加\转义
echo |awk '{print "\""}'
# 显示单引号'
# 引号说明: 最外侧的两个单引号表示awk语句,里面的一组双引号表示print语句,中间的一个单引号为想要显示的内容,但是单引号需要加\转义,转义后的单引号和awk语句的单引号冲突,所以需要在使用一组单引号括起来
echo |awk '{print "'\''"}'

# 显示双引号加字符"aa"
echo |awk '{print "\"aa\""}'
# 显示单引号加字符'aa'
echo |awk '{print "'\''aa'\''"}'
# 显示双引号和单引号"aa","bb's"
echo |awk '{print "\"aa\",\"bb'\''s\""}'

echo 'net.ipv4.ip_forward=0' |awk -F= '{printf"- sysctl:\n name: %s\n value: '\''%s'\''\n",$1,$2}' >> sysctl.yml


# 查看匹配行的下一行"/xxx/{n;p}""
$ sed -rn "/1. [ \'a-z-]+/{n;p}" a.txt
(说明)
# 尝试替换并显示"/xxx/{n;s/x/y/;p}"
$ sed -rn "/1. [ \'a-z-]+/{n;s/说明/说明123/;p}" a.txt
(说明123)
# 更改文件
$ sed -ri "/1. [ \'a-z-]+/{n;s/说明/说明123/}" a.txt
# 尝试替换并显示
$ sed -r "/^1. like$/{n;s/.*/(说明123)/}" a.txt
# 更改文件
$ sed -ri "/^1. like$/{n;s/.*/(说明123)/}" a.txt


# 匹配包含空格的单词或短语,括号可以省略
$ grep -E '^1. ([a-z-]+ )' a.txt
$ grep -E '^1. ([ a-z-]+ )' a.txt
$ grep -E '^1. ([a-z-]+ ){1,}' a.txt
$ sed -rn '/^1. ([a-z-]+ )/p' a.txt
# 全局替换g
$ sed -rn '/^1. ([a-z-]+ )/{s/ /-/g;p}' a.txt
# 仅替换第二个匹配项
$ sed -rn '/^1. ([a-z-]+ )/{s/ /-/2;p}' a.txt
# 从第二个匹配项开始替换
$ sed -rn '/^1. ([a-z-]+ )/{s/ /-/2g;p}' a.txt

# 在文件开头添加一行空行
sed '1s/^/\n/' file
# 在文件末尾添加一行空行
sed '$s/$/\n/' file
# 追加内容xxx到文件开头行,\n表示换行
sed '1s/^/xxx\n/' file
# 或
sed '1ixxx' file
# 追加内容xxx到文件末尾
sed '$axxx' file
# 追加多行内容到文件
sed '$aline1\nline2\nline3\n' file


# 在每一行的后面添加空行,包括空行后面也会添加新的空行
sed G file
# 在每一行的后面添加两行空行,包括空行后面也会添加两行空行
sed 'G;G' file
# 在第一行的后面添加空行,即在第二行添加空行
sed 1G file
# 在每一行的前面添加空行,包括空行后面也会添加新的空行
sed '{x;p;x}' file
# 在每一行的前面添加两行空行
sed '{x;p;x;x;p;x}' file
# 在第一行的前面添加空行,即在第一行添加空行
sed '1{x;p;x;}' file
# 先删除空行,然后在每一行后面添加空行
sed '/^$/d;G' file