sed (stream editor)是 Linux 上强大的流编辑器,用程序的方式来编辑文本,非常强大。

基础使用

常用参数

sed [OPTION]... {script-only-if-no-other-script} [input-file]...

A file name of - refers to the standard input stream.

-n, —quite, —slient to suppress output

-e script, —expression=script 指定脚本

-f script-file, —file=script-file 指定脚本文件

-i, edit file in-place. 默认sed 编辑器不会修改文件的数据,修改后的数据发送到 STDOUT。使用 -i 直接修改文件。

-E, -r, —regexp-extended, Use extended regular expressions rather than basic regular expressions.

-s, —separate

-u, —unbuffered Buffer both input and output as minimally as practical. (This is particularly useful if the input is coming from the likes of tail -f, and you wish to see the transformed output as soon as possible.)

  1. # 指定脚本文件
  2. $ sed -f script1.sed data1.txt
  3. $ sed s/hello/world/’ input.txt > output.txt
  4. $ sed -e s/hello/world/’ input.txt > output.txt
  5. $ sed --expression=’s/hello/world/’ input.txt > output.txt
  6. $ echo s/hello/world/’ > myscript.sed
  7. $ sed -f myscript.sed input.txt > output.txt
  8. $ sed --file=myscript.sed input.txt > output.txt
  9. # sed 默认输出到标准输出,使用 -i 直接编辑文件
  10. $ sed -i s/hello/world/’ file.txt

替换 s

s/pattern/replacement/flags

默认只替换每行中出现的第一处。有4种可用的替换标记:

  • 数字,表明新文本将替换第几处模式匹配的地方;
  • g,全部替换;
  • p,打印;
  • w file,将替换结果写到文件中;

p 替换标记常和 -n 选项一起使用。-n 选项禁止 sed 编辑器输出,二者配合使用就是只输出被替换命令修改过的行。

  1. $ echo "This is a test" | sed 's/test/big test/'
  2. This is a big test
  3. # 使用多个命令
  4. $ sed 's/brown/green/; s/dog/cat/' data2.txt
  5. # test.txt 中的 dog 替换为 cat
  6. $ sed 's/dog/cat/' test.txt
  7. # 替换每行的第二处
  8. $ sed 's/dog/cat/2' test.txt
  9. # 替换所有
  10. $ sed 's/dog/cat/g' test.txt
  11. # 替换第2个以后的dog
  12. $ sed 's/dog/cat/2g' test.txt
  13. # 打印替换的行
  14. $ sed -n 's/dog/cat/p' test.txt
  15. # 替换的行写到文件中
  16. $ sed 's/dog/cat/w out.txt' test.txt
  17. # 替换 /etc/passwd 中的 shell
  18. $ sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd
  19. # 上面不容易看懂,可以指定其它字符串分隔符
  20. $ sed 's!/bin/bash!/bin/csh!' /etc/passwd
  21. # 在开头插入
  22. $ seq 5 | sed 's/^/# /g'
  23. # 1
  24. # 2
  25. # 3
  26. # 4
  27. # 5
  28. # 在尾部插入
  29. $ seq 5 | sed 's/$/# /g'
  30. 1#
  31. 2#
  32. 3#
  33. 4#
  34. 5#

使用地址

以数字形式表示行区间

  1. # 替换第2行
  2. $ sed '2s/dog/cat/' test.txt
  3. # 替换第2-3行
  4. $ sed '2,3s/dog/cat/' test.txt
  5. # 替换从第2行开始的所有行,$ 表示最后一行
  6. $ sed '2,$s/dog/cat/' test.txt
  7. # 执行多条命令
  8. $ sed '3,${
  9. > s/fox/elephant/
  10. > s/dog/cat/
  11. > }' data1.txt
  12. # +3 表示之后的三行
  13. $ seq 5 | sed '/2/,+3s/^/# /g'
  14. 1
  15. # 2
  16. # 3
  17. # 4
  18. # 5

使用文本模式过滤器:/pattern/command

  1. # 修改用户 xiaocan 的 shell
  2. $ sed '/xiaocan/s/bash/zsh/' /etc/passwd
  3. # 使用正则表达式
  4. $ echo "This is a test" | sed -n "/test/p"
  5. # 从行首匹配
  6. $ echo "Books are great" | sed -n "/^Book/p"
  7. # 从行尾匹配
  8. $ echo "Books are great" | sed -n "/great$/p"

删除行 d

使用 d 删除行:

  1. # 删除第三行
  2. $ seq 10 | sed '3d'
  3. # 删除第1-3行
  4. $ seq 10 | sed '1,3d'
  5. # 删除包含 4 的行
  6. $ seq 4 | sed '/4/d'
  7. # 删除包含2 和 3 之间的所有行
  8. $ seq 10 | sed '/2/,/3/d'
  9. # 会删除包含 2 开始的所有行(找不到 11)
  10. $ sed 10 | sed '/2/,/11/d'
  11. # ^$ 匹配空白行,下面的例子会删除空白行
  12. $ sed '/^$/d' data.txt

插入文本 a i

sed '[address]command\new line'

i 在指定行前增加一个新行;

a 在指定行后增加一个新行;

  1. # insert
  2. $ echo "Test line 2" | sed 'i\Test line 1'
  3. Test line 1
  4. Test line 2
  5. # 可以不添加 \
  6. $ echo "Test line 2" | sed 'i Test line 1'
  7. Test line 1
  8. Test line 2
  9. # append
  10. $ echo "Test line 2" | sed 'a\Test line 1'
  11. Test line 2
  12. Test line 1
  13. # 指定行
  14. $ seq 3 | sed '1i\0'
  15. 0
  16. 1
  17. 2
  18. 3
  19. # 插入空白行
  20. $ seq 3 | sed '2i\ \'
  21. $ seq 3 | sed '2i\\'
  22. # 在最后一行添加
  23. $ seq 3 | sed '$a\4'
  24. 1
  25. 2
  26. 3
  27. 4
  28. # 添加多行,使用 \ 分割
  29. $ seq 3 | sed '$a\4\
  30. > 5\
  31. > 6'
  32. 1
  33. 2
  34. 3
  35. 4
  36. 5
  37. 6

修改行 c

  1. $ seq 5 | sed '3c\change this line'
  2. 1
  3. 2
  4. change this line
  5. 4
  6. 5
  7. # 用多行替换这一行
  8. $ sed 5 | sed '2,3c/change this line'
  9. 1
  10. change this line
  11. 4
  12. 5

转换命令 y

一对一字符替换:[address]y/inchars/outchars/,inchars 和 outchars 的长度要一样

  1. $ seq 3 | sed 'y/123/789/'
  2. 7
  3. 8
  4. 9
  5. # 默认就是全局替换,
  6. $ echo "This 1 is a test of 1 try." | sed 'y/123/456/'
  7. This 4 is a test of 4 try.

打印 p

p 打印文本行;

= 打印行号;

l 列出行(list),可以打印数据流中的文本和不可打印的 ASCII 字符。

p 常和 -n 一起使用:

  1. $ seq 5 | sed -n '/5/p'
  2. 5
  3. $ seq 5 | sed -n '2,3p'
  4. 2
  5. 3
  6. $ seq 5 | sed -n '/2/{
  7. # 打印原来行
  8. > p
  9. # 打印替换后的行
  10. > s/2/222/p
  11. > }'
  12. 2
  13. 222
  14. # 打印行号
  15. $ sed '=' data2.txt
  16. 1
  17. One line of test text.
  18. 2
  19. Two line of test text.
  20. 3
  21. Three line of test text.
  22. $ sed -n '/One/{
  23. > =
  24. > p
  25. > }' data2.txt
  26. 1
  27. One line of test text.
  28. # 测试 l
  29. $ cat data2.txt
  30. One line of test text.
  31. Two line of test text.
  32. Three line of test text.
  33. Four line of test text.
  34. $ sed -n 'l' data2.txt
  35. One line of test text.$
  36. Two line of test text.$
  37. Three line of test text.$
  38. Four\tline\tof\ttest\ttext.$

写入文件 w

[address]w filename

  1. $ seq 10 | sed '1,3w test.txt'
  2. $ sed '/xiaocan/w xiaocan.txt' /etc/passwd

读取数据 r

[address]r filename

地址只能用单独一个行号或者文本模式地址。读取文件,插入到指定地址之后。

  1. $ cat data4.txt
  2. This is a test of the test script;
  3. This is the second test of the test script;
  4. $ seq 3 | sed '2r data4.txt'
  5. 1
  6. 2
  7. This is a test of the test script;
  8. This is the second test of the test script;
  9. 3
  10. # 在最后添加
  11. $ seq 3 | sed '$r data4.txt'
  12. $ sed '/LIST/{
  13. # 替换占位符
  14. > r data1.txt
  15. # 删除原来的占位符
  16. > d
  17. > }' out.txt

排除命令 !

使用 ! 用排除命令:

  1. # 不打印包含3 的行
  2. $ seq 3 | sed -n '/3/!p'
  3. 1
  4. 2

退出码 q

0 Successful completion.

1 Invalid command, invalid syntax, invalid regular expression

2 输入的文件不能打开(文件找不到或者没有权限)

4 An I/O error, or a serious processing error during runtime, GNU sed aborted immediately.

使用 Q 或者 q 指定退出码:

  1. $ echo | sed Q42 ; echo $?
  2. 42
  3. # 输出直到遇到 foo 开头的行
  4. $ sed '/^foo/q42' input.txt > output.txt

模式替换 & \1

& 可以用来代表替换命令中匹配的模式。

  1. $ echo "The cat sleeps in his hat." | sed 's/.at/"&"/g'
  2. The "cat" sleeps in his "hat".

sed 用圆括号来定义替换模式中的子模式,然后可以用 \1 \2 等引用匹配的字模式。

  1. # 圆括号需要转义
  2. $ echo "The System Administrator manual" | sed 's/\(System\) Administrator/\1 User/'
  3. The System User manual
  4. $ echo "The furry hat is pretty" | sed 's/furry \(.at\)/\1/'
  5. The hat is pretty

命令分组

  1. # 对3行到第6行,执行命令/This/d
  2. $ sed '3,6 {/This/d}' pets.txt
  3. # 对3行到第6行,匹配/This/成功后,再匹配/fish/,成功后执行d命令
  4. $ sed '3,6 {/This/{/fish/d}}' pets.txt
  5. # 从第一行到最后一行,如果匹配到This,则删除之;如果前面有空格,则去除空格
  6. $ sed '1,${/This/d;s/^ *//g}' pets.txt

多行命令

N:将数据流中的下一行加进来创建一个多行组来处理。

D:删除多行组中的一行。

P:打印多行组中的一行。

next 命令 N

n 移动到下一行

  1. $ cat data1.txt
  2. This is the header line.
  3. This is a data line.
  4. This is the last line.
  5. # 删除第一行后的那行
  6. $ sed '/header/{n ; d}' data1.txt
  7. This is the header line.
  8. This is a data line.
  9. This is the last line.

N 将下一行与当前行合并处理

  1. $ cat data2.txt
  2. One line of test text.
  3. Two line of test text.
  4. Three line of test text.
  5. Four line of test text.
  6. # 合并两行
  7. $ sed '/Two/{N ; s/\n/ /}' data2.txt
  8. One line of test text.
  9. Two line of test text. Three line of test text.
  10. Four line of test text.
  11. # 如何将下面的 System Administraor 替换成 Desktop User 呢?
  12. # 注意第一行和第二行跨行了
  13. $ cat data3.txt
  14. On Tuesday, the Linux System
  15. Administrator's group meeting will be held.
  16. All System Administrators should attend.
  17. # 为啥两处的替换都没有生效呢?
  18. # 第一个是因为不匹配;第二个是因为读取第三行的时候,没有下一行了,所以sed命令就停止了
  19. $ sed 'N ; s/System Administrator/Desktop User/' data3.txt
  20. On Tuesday, the Linux System
  21. Administrator's group meeting will be held.
  22. All System Administrators should attend.
  23. # 中间添加一个通配符,可以匹配换行,第一处成功替换了
  24. $ sed 'N ; s/System.Administrator/Desktop User/' data3.txt
  25. On Tuesday, the Linux Desktop User's group meeting will be held.
  26. All System Administrators should attend.
  27. # 使用 $! 排除最后一行
  28. $ sed '$!N ; s/System\nAdministrator/Desktop\nUser/; s/System Administrator/Desktop User/' data3.txt
  29. On Tuesday, the Linux Desktop
  30. User's group meeting will be held.
  31. All Desktop Users should attend.
  32. # N 前面的替换匹配单行的,N 后面的替换匹配多行的,这样就可以了。
  33. $ sed 's/System Administrator/Desktop User/ ; N ; s/System\nAdministrator/Desktop\nUser/' data3.txt
  34. On Tuesday, the Linux Desktop
  35. User's group meeting will be held.
  36. All Desktop Users should attend.
  37. # 但是,如果文本是这样该任何替换呢?
  38. $ sed 's/System Administrator/Desktop User/ ; N ; s/System\nAdministrator/Desktop\nUser/' data3.txt
  39. All Desktop Users should attend.
  40. On Tuesday, the Linux System
  41. Administrator's group meeting will be held.

多行删除 D

D 删除模式空间中的第一行。

  1. $ cat data3.txt
  2. On Tuesday, the Linux System
  3. Administrator's group meeting will be held.
  4. All System Administrators should attend.
  5. # 删除了第一行
  6. $ sed 'N; /System\nAdministrator/D' data3.txt
  7. Administrator's group meeting will be held.
  8. All System Administrators should attend.

多行打印 P

p 打印模式空间中的第一行。

  1. $ sed -n 'N; /System\nAdministrator/P' data3.txt
  2. On Tuesday, the Linux System

Pattern space & hold space

pattern space 是 sed 用来处理文本的缓冲区。hold space 是另外一个区域,可以用来临时保存一些行。

h 将 pattern space 复制到 hold space

H 将 pattern space 附加到 hold space

g 将 hold space 复制到 pattrn space

G 将 hold space 附加到 pattern sapce

x 交换 pattern space 和 hold space 的内容

通常,在使用 hH 命令之后,还要用 gG 命令把内容拿回来。

反转文件中行的顺序

  1. $ cat data2.txt
  2. One line of test text.
  3. Two line of test text.
  4. Three line of test text.
  5. Four line of test text.
  6. $ sed -n '{1!G ; h ; $p}' data2.txt
  7. Four line of test text.
  8. Three line of test text.
  9. Two line of test text.
  10. One line of test text.
  11. # 或者
  12. $ sed '{1!G ; h ; $!d}' data2.txt
  13. Four line of test text.
  14. Three line of test text.
  15. Two line of test text.
  16. One line of test text.
  17. # tac 命令也可以反转行
  18. $ tac data2.txt
  19. Four line of test text.
  20. Three line of test text.
  21. Two line of test text.
  22. One line of test text.

image.png

改变流

分支 b

sed 编辑器提供了一种方法,可以基于地址、地址模式或地址区间排除一整块命令。

[address]b [label] address 参数指定哪些行会触发分支命令。label 指定了要跳转的位置,如果没有,会跳转到脚本的结尾。

  1. $ cat data2.txt
  2. One line of test text.
  3. Two line of test text.
  4. Three line of test text.
  5. Four line of test text.
  6. # 第2行和第三行不执行替换命令
  7. $ sed '{2,3b ; s/line/Line/ ; s/text/line/}' data2.txt
  8. One Line of test line.
  9. Two line of test text.
  10. Three line of test text.
  11. Four Line of test line.
  12. # 匹配行执行标签之后的命令,其它行执行所有的命令
  13. $ sed '{/One/b jump1; s/test text/no jump/
  14. > :jump1
  15. > s/line/Line/}' data2.txt
  16. One Line of test text.
  17. Two Line of no jump.
  18. Three Line of no jump.
  19. Four Line of no jump.

测试 t

t 测试命令会根据替换命令的结果跳转到某个标签。相当于 if-then 语句。

[address]t [label]

  1. $ cat data2.txt
  2. One line of test text.
  3. Two line of test text.
  4. Three line of test text.
  5. Four line of test text.
  6. # 不匹配的行执行 t 后面的替换命令
  7. $ sed '{
  8. > s/One/matched/
  9. > t
  10. > s/line/no match/
  11. > }' data2.txt
  12. matched line of test text.
  13. Two no match of test text.
  14. Three no match of test text.
  15. Four no match of test text.
  16. $ echo "This, is, a, test, to, remove, commas." | sed -n '{
  17. > :start
  18. > s/,//1p
  19. > t start
  20. > }'
  21. This is, a, test, to, remove, commas.
  22. This is a, test, to, remove, commas.
  23. This is a test, to, remove, commas.
  24. This is a test to, remove, commas.
  25. This is a test to remove, commas.
  26. This is a test to remove commas.

使用示例

加倍行间距

  1. $ cat data3.txt
  2. On Tuesday, the Linux System
  3. Administrator's group meeting will be held.
  4. All System Administrators should attend.
  5. # G 会将 hold space 内容附加到 pattern space 内容后面,默认是空行
  6. $ sed 'G' data3.txt
  7. On Tuesday, the Linux System
  8. Administrator's group meeting will be held.
  9. All System Administrators should attend.
  10. $
  11. # 最后一行不添加空白行
  12. $ sed '$!G' data3.txt
  13. On Tuesday, the Linux System
  14. Administrator's group meeting will be held.
  15. All System Administrators should attend.
  16. $
  17. # 如果文件中存在空白行,先删除空白行,再添加
  18. $ sed '/^$/d ; $!G' data3.txt
  19. On Tuesday, the Linux System
  20. Administrator's group meeting will be held.
  21. All System Administrators should attend.

打印行号

  1. # 打印行号,但是不够美观
  2. $ sed '=' data2.txt
  3. 1
  4. One line of test text.
  5. 2
  6. Two line of test text.
  7. 3
  8. Three line of test text.
  9. # 删除行号和内容之间的换行符
  10. $ sed '=' data2.txt | sed 'N ; s/\n/ /'
  11. 1 One line of test text.
  12. 2 Two line of test text.
  13. 3 Three line of test text.

打印末尾行

  1. $ sed -n '$p' data2.txt
  2. Three line of test text.
  3. # 打印最后的5行,比较难理解,还是直接用 seq 10 | tail -5 吧
  4. $ seq 10 | sed '{
  5. > :start
  6. > $q ; N ; 6,$D
  7. > b start
  8. > }'
  9. 6
  10. 7
  11. 8
  12. 9
  13. 10

删除行

删除连续的空白行

  1. $ cat data5.txt
  2. This is line one.
  3. This is line two.
  4. This is line Three.
  5. This is line four.
  6. $
  7. $ sed '/./,/^$/!d' data5.txt
  8. This is line one.
  9. This is line two.
  10. This is line Three.
  11. This is line four.

区间 /.//^$/ ,开始地址匹配任何含有至少一个字符的行,结束地址匹配一个空行。

  1. # 打印非空行
  2. $ sed -n '/./p' data5.txt
  3. This is line one.
  4. This is line two.
  5. This is line Three.
  6. This is line four.

删除开头的空白行

  1. $ cat data6.txt
  2. This is line one.
  3. This is line two.
  4. This is line Three.
  5. This is line four.
  6. $
  7. # 从有内容的行到结尾的行不删除,其它都删除
  8. $ sed '/./,$!d' data6.txt
  9. This is line one.
  10. This is line two.
  11. This is line Three.
  12. This is line four.

删除结尾的空白行

  1. $ cat data6.txt
  2. This is line one.
  3. This is line two.
  4. This is line Three.
  5. This is line four.
  6. $
  7. $ sed '{
  8. > :start
  9. > /^\n*$/{$d ; N ; b start }
  10. > }' data6.txt
  11. This is line one.
  12. This is line two.
  13. This is line Three.
  14. This is line four.
  15. $

这个脚本里面还有花括号,这允许在整个脚本中将一些命令分组。该命令组会被应用在指定的地址模式上。

地址模式能够匹配含有0个或多个换行符的行。如果找到这样的行,而且还是最后一行,就删除它。如果不是最后一行,N 命令会将下一行附加到它后面,分支命令会跳到循环起始位置重新开始。

删除标签

  1. $ cat HTML.txt
  2. <b>This</b> is what <span style="text-decoration: underline;">I</span> meant. Understand?
  3. # 其中的'[^>]' 指定了除了>的字符重复0次或多次。
  4. $ sed 's/<[^>]*>//g' HTML.txt
  5. This is what I meant. Understand?

参考

GNU sed home page.

https://www.gnu.org/software/sed/manual/sed.pdf

http://sed.sourceforge.net/