本文主要转载自知乎:学习 shell 有什么好书推荐? - 嵌入式小傻瓜的回答 - 知乎

Sed 是什么?

Sed 是 Stream editor 的简称,即文本流编辑器。

Linux中的sed命令使用说明和技巧 - 图1

它可以对文件执行许多操作,例如搜索、查找和替换、插入或删除。

在 UNIX 中,Sed 命令最常见的用途是查找和替换。

通过使用 Sed,我们甚至可以在不打开文件的情况下编辑文件,这比首先在 VI 编辑器中打开该文件然后更改它要快得多。

Sed 怎么用?

接下来,所有的操作都基于下面这个文件:

  1. $ vi employee.txt
  2. 101,John Doe,CEO
  3. 102,Jason Smith,IT Manager
  4. 103,Raj Reddy,Sysadmin
  5. 104,Anand Ram,Developer
  6. 105,Jane Miller,Sales Manager

Sed 工作流?

Linux中的sed命令使用说明和技巧 - 图2

Sed 每次会读取一行文本到 pattern space (类似缓冲区)里,然后执行用户指定的命令 (sed-commands),然后打印出 pattern space 的内容并清空 pattrn space,循环执行上面的 3 个步骤。

语法:

  1. sed [options] {sed-commands} {input-file}

一个具体的例子:

  1. # 等效于 cat employee.txt
  2. $ sed -n 'p' employee.txt
  3. 101,John Doe,CEO
  4. 102,Jason Smith,IT Manager
  5. 103,Raj Reddy,Sysadmin
  6. 104,Anand Ram,Developer
  7. 105,Jane Miller,Sales Manager

-n 对应 options。Sed 默认会打印 pattern space 里的内容,-n 表示禁止打印

‘p’ 对应 sed-commands,p 命令表示打印。

employee.txt 对应 input-file。

执行多条命令:

  1. # 筛选出以 101 或 103 开头的行
  2. $ sed -n -e '/^101/ p' -e '/^103/ p' employee.txt
  3. 101,John Doe,CEO
  4. 103,Raj Reddy,Sysadmin

打印操作(p 命令):

我们可以在 p 命令前加一些修饰参数,用于指定 address range 或 pattern range。

  1. # 只打印第 2 行
  2. $ sed -n '2 p' employee.txt
  3. 102,Jason Smith,IT Manager
  4. # 打印第 1 到 4 行
  5. $ sed -n '1,4 p' employee.txt
  6. 101,John Doe,CEO
  7. 102,Jason Smith,IT Manager
  8. 103,Raj Reddy,Sysadmin
  9. 104,Anand Ram,Developer
  10. # 打印第 2 到最后一行
  11. $ sed -n '2,$ p' employee.txt
  12. 102,Jason Smith,IT Manager
  13. 103,Raj Reddy,Sysadmin
  14. 104,Anand Ram,Developer
  15. 105,Jane Miller,Sales Manager
  16. # 打印匹配 “Jane” 的行
  17. $ sed -n '/Jane/ p' employee.txt
  18. 105,Jane Miller,Sales Manager
  19. # 打印从匹配 “Raj” 起始,直到文件末尾的行
  20. $ sed -n '/Raj/,$ p' employee.txt
  21. 103,Raj Reddy,Sysadmin
  22. 104,Anand Ram,Developer
  23. 105,Jane Miller,Sales Manager
  24. # 打印从匹配 “Raj” 起始,直到匹配 “Jane” 的行
  25. $ sed -n '/Raj/,/Jane/ p' employee.txt
  26. 103,Raj Reddy,Sysadmin
  27. 104,Anand Ram,Developer
  28. 105,Jane Miller,Sales Manager

删除操作(d 命令):

删除操作和打印操作很类似,只是将命令 p 换成命令 d

  1. sed 'd' employee.txt
  2. sed '2 d' employee.txt
  3. sed '1,4 d' employee.txt
  4. sed '2,$ d' employee.txt
  5. sed '1~2 d' employee.txt
  6. sed '/Manager/ d' employee.txt
  7. sed '/Jason/,4 d' employee.txt
  8. sed '/Raj/,$ d' employee.txt
  9. sed '/Raj/,/Jane/ d' employee.txt

写操作(w命令)

Sed 默认是将 pattern space 的数据写到 stdout,用 w 命令可以将数据写到指定文件。

  1. sed -n 'w output.txt' employee.txt
  2. sed -n '2 w output.txt' employee.txt
  3. sed -n '1,4 w output.txt' employee.txt
  4. sed -n '2,$ w output.txt' employee.txt
  5. sed -n '1~2 w output.txt' employee.txt
  6. sed -n '/Jane/ w output.txt' employee.txt
  7. sed -n '/Jason/,4 w output.txt' employee.txt
  8. sed -n '/Raj/,$ w output.txt' employee.txt
  9. sed -n '/Raj/,/Jane/ w output.txt' employee.txt

替换操作(s 命令):

Sed 最牛掰的命令就是替换,先看语法:

  1. sed '[address-range|pattern-range] s/original-
  2. string/replacement-string/[substitute-flags]' inputfile

range 用于定位,是可选参数;

flags 用于修饰替换的行为,是可选参数;

先看 2 个最简单的例子:

  1. # 将所有的 “Manager” 都替换为 "Director"
  2. $ sed 's/Manager/Director/' employee.txt
  3. 101,John Doe,CEO
  4. 102,Jason Smith,IT Director
  5. 103,Raj Reddy,Sysadmin
  6. 104,Anand Ram,Developer
  7. 105,Jane Miller,Sales Director
  8. # 将包含 “Sales” 的行里的 "Manager" 替换成 "Director"
  9. $ sed '/Sales/s/Manager/Director/' employee.txt
  10. 101,John Doe,CEO
  11. 102,Jason Smith,IT Manager
  12. 103,Raj Reddy,Sysadmin
  13. 104,Anand Ram,Developer
  14. 105,Jane Miller,Sales Director

默认情况下,s 命令只会替换一行中第一处匹配的地方,想全局替换,要使用 Global Flag:

  1. # 只替换第一处
  2. $ sed 's/a/A/' employee.txt
  3. 101,John Doe,CEO
  4. 102,JAson Smith,IT Manager
  5. 103,RAj Reddy,Sysadmin
  6. 104,AnAnd Ram,Developer
  7. 105,JAne Miller,Sales Manager
  8. # 全局替换
  9. $ sed 's/a/A/g' employee.txt
  10. 101,John Doe,CEO
  11. 102,JAson Smith,IT MAnAger
  12. 103,RAj Reddy,SysAdmin
  13. 104,AnAnd RAm,Developer
  14. 105,JAne Miller,SAles MAnAger

Number Flag 可以用于指定要处理第几处的匹配项:

  1. # 只替换第 2 个 'a'
  2. $ sed 's/a/A/2' employee.txt
  3. 101,John Doe,CEO
  4. 102,Jason Smith,IT MAnager
  5. 103,Raj Reddy,SysAdmin
  6. 104,Anand RAm,Developer
  7. 105,Jane Miller,SAles Manager

还有一些用得比较少的 Flag:

  1. # Print Flag (p flag) 用于打印匹配行
  2. $ sed -n 's/John/Johnny/p' employee.txt
  3. 101,Johnny Doe,CEO
  4. # Write Flag (w flag) 用于写入
  5. $ sed -n 's/John/Johnny/w output.txt' employee.txt
  6. $ cat output.txt
  7. 101,Johnny Doe,CEO
  8. # Ignore Case Flag (i flag) 用于忽略大小写
  9. $ sed 's/john/Johnny/i' employee.txt

多个 Flag 可以组合在一起使用:

  1. $ sed -n 's/Manager/Director/gipw output.txt'
  2. employee.txt
  3. 102,Jason Smith,IT Director
  4. 105,Jane Miller,Sales Director

Sed 替换操作默认的分隔符是 ‘/‘,如果要处理的文本含
有 ‘/‘ 的话,可以换一个分隔符:

  1. # 将 /usr/local/bin 替换成 /usr/bin
  2. sed 's|/usr/local/bin|/usr/bin|' path.txt
  3. sed 's^/usr/local/bin^/usr/bin^' path.txt
  4. sed 's@/usr/local/bin@/usr/bin@' path.txt
  5. sed 's!/usr/local/bin!/usr/bin!' path.txt

引用和正则表达式:

& 可以用来引用匹配项:

  1. # 给 ID 号加上 []
  2. $ sed 's/^[0-9][0-9][0-9]/[&]/g' employee.txt
  3. [101],John Doe,CEO
  4. [102],Jason Smith,IT Manager
  5. [103],Raj Reddy,Sysadmin
  6. [104],Anand Ram,Developer
  7. [105],Jane Miller,Sales Manager

跟在正则表达式中一样,sed 中也可以使用分组。分组以 ‘(‘ 开始,以 ‘)‘ 结束。分组后就可以按组来引用了:

  1. $ sed 's/\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/g' employee.txt
  2. 101,CEO
  3. 102,IT Manager
  4. 103,Sysadmin
  5. 104,Developer
  6. 105,Sales Manager

[^,] 表示除了’,’ 之外的任意字符,* 表示0个或者多个。

第 1 个分组 ([^,]*) ,匹配雇员 ID,在后面用 ‘\1’ 来引用。

第 3 个分组 ([^,]*) ,匹配雇员职位,在后面用 ‘\3’ 来引用。

Sed 一般搭配正则表达式使用,关于正则表达式的用法,则需要再写一篇文章才能说清楚。

到此,Sed 比较常用的用法就介绍完毕了。

总结

Sed 是 UNIX 世界的两大文本处理神器之一,
它能帮你对文本进行删除、替换等操作,熟练掌握它将大大增加你的文本处理能力。

使用 Sed 需要记住下面几个概念

Flow,Sed 的工作流程;

Command,Sed 支持哪些命令?

Flag,Sed 命令支持哪些 flag?

正则,Sed 如何搭配正则表达式?

最后,建议读者朋友们读完本文后,亲自去看看 《sed and awk 101 hacks》 这本书,肯定会跟我一样受益匪浅的。

引用书里的一句话:

Enhance Your UNIX and Linux Life with Sed and Awk.