本文主要转载自知乎:学习 shell 有什么好书推荐? - 嵌入式小傻瓜的回答 - 知乎
Sed 是什么?
Sed 是 Stream editor 的简称,即文本流编辑器。
它可以对文件执行许多操作,例如搜索、查找和替换、插入或删除。
在 UNIX 中,Sed 命令最常见的用途是查找和替换。
通过使用 Sed,我们甚至可以在不打开文件的情况下编辑文件,这比首先在 VI 编辑器中打开该文件然后更改它要快得多。
Sed 怎么用?
接下来,所有的操作都基于下面这个文件:
$ vi employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
Sed 工作流?
Sed 每次会读取一行文本到 pattern space (类似缓冲区)里,然后执行用户指定的命令 (sed-commands),然后打印出 pattern space 的内容并清空 pattrn space,循环执行上面的 3 个步骤。
语法:
sed [options] {sed-commands} {input-file}
一个具体的例子:
# 等效于 cat employee.txt
$ sed -n 'p' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
-n 对应 options。Sed 默认会打印 pattern space 里的内容,-n 表示禁止打印
‘p’ 对应 sed-commands,p 命令表示打印。
employee.txt 对应 input-file。
执行多条命令:
# 筛选出以 101 或 103 开头的行
$ sed -n -e '/^101/ p' -e '/^103/ p' employee.txt
101,John Doe,CEO
103,Raj Reddy,Sysadmin
打印操作(p 命令):
我们可以在 p 命令前加一些修饰参数,用于指定 address range 或 pattern range。
# 只打印第 2 行
$ sed -n '2 p' employee.txt
102,Jason Smith,IT Manager
# 打印第 1 到 4 行
$ sed -n '1,4 p' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
# 打印第 2 到最后一行
$ sed -n '2,$ p' employee.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
# 打印匹配 “Jane” 的行
$ sed -n '/Jane/ p' employee.txt
105,Jane Miller,Sales Manager
# 打印从匹配 “Raj” 起始,直到文件末尾的行
$ sed -n '/Raj/,$ p' employee.txt
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
# 打印从匹配 “Raj” 起始,直到匹配 “Jane” 的行
$ sed -n '/Raj/,/Jane/ p' employee.txt
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
删除操作(d 命令):
删除操作和打印操作很类似,只是将命令 p 换成命令 d
sed 'd' employee.txt
sed '2 d' employee.txt
sed '1,4 d' employee.txt
sed '2,$ d' employee.txt
sed '1~2 d' employee.txt
sed '/Manager/ d' employee.txt
sed '/Jason/,4 d' employee.txt
sed '/Raj/,$ d' employee.txt
sed '/Raj/,/Jane/ d' employee.txt
写操作(w命令)
Sed 默认是将 pattern space 的数据写到 stdout,用 w 命令可以将数据写到指定文件。
sed -n 'w output.txt' employee.txt
sed -n '2 w output.txt' employee.txt
sed -n '1,4 w output.txt' employee.txt
sed -n '2,$ w output.txt' employee.txt
sed -n '1~2 w output.txt' employee.txt
sed -n '/Jane/ w output.txt' employee.txt
sed -n '/Jason/,4 w output.txt' employee.txt
sed -n '/Raj/,$ w output.txt' employee.txt
sed -n '/Raj/,/Jane/ w output.txt' employee.txt
替换操作(s 命令):
Sed 最牛掰的命令就是替换,先看语法:
sed '[address-range|pattern-range] s/original-
string/replacement-string/[substitute-flags]' inputfile
range 用于定位,是可选参数;
flags 用于修饰替换的行为,是可选参数;
先看 2 个最简单的例子:
# 将所有的 “Manager” 都替换为 "Director"
$ sed 's/Manager/Director/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Director
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Director
# 将包含 “Sales” 的行里的 "Manager" 替换成 "Director"
$ sed '/Sales/s/Manager/Director/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Director
默认情况下,s 命令只会替换一行中第一处匹配的地方,想全局替换,要使用 Global Flag:
# 只替换第一处
$ sed 's/a/A/' employee.txt
101,John Doe,CEO
102,JAson Smith,IT Manager
103,RAj Reddy,Sysadmin
104,AnAnd Ram,Developer
105,JAne Miller,Sales Manager
# 全局替换
$ sed 's/a/A/g' employee.txt
101,John Doe,CEO
102,JAson Smith,IT MAnAger
103,RAj Reddy,SysAdmin
104,AnAnd RAm,Developer
105,JAne Miller,SAles MAnAger
Number Flag 可以用于指定要处理第几处的匹配项:
# 只替换第 2 个 'a'
$ sed 's/a/A/2' employee.txt
101,John Doe,CEO
102,Jason Smith,IT MAnager
103,Raj Reddy,SysAdmin
104,Anand RAm,Developer
105,Jane Miller,SAles Manager
还有一些用得比较少的 Flag:
# Print Flag (p flag) 用于打印匹配行
$ sed -n 's/John/Johnny/p' employee.txt
101,Johnny Doe,CEO
# Write Flag (w flag) 用于写入
$ sed -n 's/John/Johnny/w output.txt' employee.txt
$ cat output.txt
101,Johnny Doe,CEO
# Ignore Case Flag (i flag) 用于忽略大小写
$ sed 's/john/Johnny/i' employee.txt
多个 Flag 可以组合在一起使用:
$ sed -n 's/Manager/Director/gipw output.txt'
employee.txt
102,Jason Smith,IT Director
105,Jane Miller,Sales Director
Sed 替换操作默认的分隔符是 ‘/‘,如果要处理的文本含
有 ‘/‘ 的话,可以换一个分隔符:
# 将 /usr/local/bin 替换成 /usr/bin
sed 's|/usr/local/bin|/usr/bin|' path.txt
sed 's^/usr/local/bin^/usr/bin^' path.txt
sed 's@/usr/local/bin@/usr/bin@' path.txt
sed 's!/usr/local/bin!/usr/bin!' path.txt
引用和正则表达式:
& 可以用来引用匹配项:
# 给 ID 号加上 []
$ sed 's/^[0-9][0-9][0-9]/[&]/g' employee.txt
[101],John Doe,CEO
[102],Jason Smith,IT Manager
[103],Raj Reddy,Sysadmin
[104],Anand Ram,Developer
[105],Jane Miller,Sales Manager
跟在正则表达式中一样,sed 中也可以使用分组。分组以 ‘(‘ 开始,以 ‘)‘ 结束。分组后就可以按组来引用了:
$ sed 's/\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/g' employee.txt
101,CEO
102,IT Manager
103,Sysadmin
104,Developer
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.