当你看到这篇文章时,你也许应该知道什么是Sed了,不知道的请自行Google。为什么说要“玩”Sed,而并不是“认真”的去学习呢?
大家都知道,在Unix和Linux下,各种命令的各种奇特技巧是数不胜数,Sed也不例外,而我这里只“玩”一些最基本的使用,而那些“高深”的技巧,就留在日后慢慢“打怪升级”吧。接下来就来说说我是如何“玩”Sed的。
现在需要将下列文本中的SZ换成SH,看看Sed
如何来完成这项工作。
测试文件addressList内容:
LiuDong, 203 King Road, BJ
WuHai, 220 ShenNan Road, SZ
LiuMei, 210 ShenNan Road, SZ
WuLi, 12 HouHai, BJ
Jack Chen, 765 Huhhot Road, NM
BaoZhuzi, 452 XinHua Road, NM
FengZhen, 309 XinHua Road, NM
YiXin, 405 XiAn Road, SZ
使用Sed只需一行命令就可以搞定。
sed 's/SZ/SH/' addressList
输出:
LuDong, 203 King Road, BJ
WuHai, 220 ShenNan Road, SH
LiuMei, 210 ShenNan Road, SH
WuLi, 12 HouHai, BJ
Jack Chen, 765 Huhhot Road, NM
BaoZhuzi, 452 XinHua Road, NM
FengZhen, 309 XinHua Road, NM
YiXin, 405 XiAn Road, SH
可以看到,一行简单的命令就可以将字符串“SZ”替换成“SH”。先简单的说说那一行命令。sed
表示执行sed命令,s/SZ/SH
中s
在Sed表示替换的意思,也就是说将SZ替换为SH,最后的就是文件名了。运行以后,将会直接输出运行结果,而原文件并不会被修改,如果你想直接修改原文件,你可以这样,使用-i
选项:
sed -i 's/SZ/SH/' addressList
好了,这就是Sed,怎么样?
很多时候,我们的脚本不可能向上面那么短,也不可能就只有简简单单的一个脚本,这个时候就需要将创建脚本文件了,然后对目标文件执行脚本文件即可。
sed -f scriptfile file
接下来就写一个最简单的Sed脚本。
vi sedReplace
输入一下内容:
s/BJ/HN/ #将每一行找到的第一个BJ替换为HN
s/SZ/AH,AH/ #将每一行的第一个SZ替换为AH,AH
s/AH/NM/g #将每一行上找到的所有AH替换为NM
在命令行上输入:
sed -f sedReplace addressList
输出结果为:
LuDong, 203 King Road, HN
WuHai, 220 ShenNan Road, NM,NM
LiuMei, 210 ShenNan Road, NM,NM
WuLi, 12 HouHai, HN
Jack Chen, 765 Huhhot Road, NM
BaoZhuzi, 452 XinHua Road, NM
FengZhen, 309 XinHua Road, NM
YiXin, 405 XiAn Road, NM,NM
你能想清楚为什么输出是这样的吗?如果不明白,接着看Sed的基本工作原理。
学习东西,就要学习原理的东西,只有原理搞明白了,万变不离其宗。现在就对Sed最基本的原理进行分析。
Sed是一个流编辑器,何为流编辑器呢?就是指Sed每次只从文件读入一行,然后对该行进行处理,然后输出;接着读入下一行,直至整个文件被读取完;在此过程中,整个文件就好比流水一样,逐行被读入处理,然后再逐行输出。
下面就用一副图来说说Sed的基本工作原理。
由于Sed是在那个PC内存只有几兆的年代开发出来的,所以Sed不会将待处理文档的所有内容一次性的读入内存,而是每次从待处理文件中读取一行到pattern space
,然后对pattern space
中的内容依次执行每一个命令,最后输出pattern space
中的内容并清空pattern space
。由此可见,Sed并不会对原文件进行任何修改(在没有加-i选项的情况下)。
在上图中还有一个hold space
我没有具体的说。当涉及到hold space
时,都会是Sed的一些高级用法了,所以此处我不做总结,如有兴趣,可以参见这篇文章《Sed高级用法》。
现在你知道了Sed的原理,但是你还是无法痛快的写出Sed脚本。这就好比你知道米饭是用米来做的,但是你却没法用米做出米饭。就算你知道了所有的“大道理”,却不知晓最简单的命令,你依然寸步难行——巧妇难为无米之炊;所以,这一节我将重点总结Sed中的基本命令。
先看看使用Sed命令的两种最基本的格式。
sed [options] 'sed_command' file(s)
sed [options] -f sed_script file(s)
关于常用的options请参见文章最后的附录部分。再来看看Sed中address
的概念。
在使用Sed命令或脚本处理文件时,在默认情况下,Sed会扫描待处理文件的每一行,然后进行处理;当然了,我们可以改变这种情况,可以指定一个address
,只对特定行进行处理;现在问题来了,我们如何指定这个address
呢?下面表格详细的列举了常用的指定address
的几种方式。
书写格式 | 说明 | 举例 |
---|---|---|
number | 直接指定行号,只匹配特定行号,只对特定行进行操作 | 将第二行的SH换成NM:sed ’2s/SH/NM/’ addressList |
first~step | first为起始行,step为递增量 | 只输入奇数行:sed -n ’1~2p’ addressList |
$ | 匹配文件最后一行 | 打印文件最后一行:sed -n ‘$p’ addressList |
/regexp/ | 正则表达式匹配对应的行 | 输出包含NM的行:sed -n ‘/NM/p’ addressList |
addr1,+N | 匹配从 addr1 的行开始,直到下面的 N 行 | 输出2~5行:sed -n ’2,+3p’ addressList |
Sed中地址概念说完以后,再来看看Sed中最基本的增、删、改、查等这些基本的命令。
命令 | 说明 | 举例 |
---|---|---|
s(替换命令) | 格式:[address1[,address2]]s/pattern/replacement/flag;将pattern匹配的内容使用replacement进行替换;flag取值请参见附录中的FLAG常用取值 | sed -r “2,3s/TH|YD/JT/2″ 201509.log |
d(删除命令) | 格式:[address1[,address2]]d | sed ‘/TH/d’ 201509.log |
a(追加命令) | 格式:[address]a text,在匹配行的下面追加一行 | sed ‘a HG’ 201509.log |
i(插入命令) | 格式:[address]i text,在匹配行的前面追加一行 | sed ‘i HG’ 201509.log |
c(更改命令) | 格式:[address1[,address2]]c text,用text来替代(改变)由地址选定的行。当指定的是一个行范围时,将所有这些行作为一个组并用text取代。 | sed ’1,2c XG’ 201509.log |
你可以在吃早点的间隙、挤地铁的间隙、坐马桶的间隙、又或撸啊撸的间隙,拿起手机看看这篇文章。总之,这是一篇让你Get一项新技能,而又不费时的文章。最后奉上Sed的官方文档,你现在需要的是行动。
2015年9月20日 于呼和浩特。
常用命令选项总结
选项 | 说明 |
---|---|
-i[suffix] | 直接将修改写入原文件;如果提供了SUFFIX,则对原文件file先进行备份,例如:sed -i_bak.20150919 ‘cmd’ file1 会先生成file1_bak.20150919这个内容与文件file1一模一样的文件,然后再对file1文件进行更改 |
-e | 使用多个Sed指令;如果有多个Sed指令需要执行,而又不想写Sed脚本,就可以使用该选项。例如:sed -e ‘cmd1′ -e ‘cmd2′ … -e ‘cmdN’ file(s) |
-n | 禁用默认输出;在默认情况下,Sed会将输入内容的每行都输出,-n可以禁用默认输出。通常和p 命令一起使用,只输出pattern space中改变了的行 |
-r | 可以使用GNU扩展的正则表达式,在一些古董机器上非常有用 |
FLAG常用取值总结
flag | 说明 |
---|---|
n | 1~512之间的一个数字,表示对匹配模式的每行中第n次出现的情况进行替换 |
g | 全局替换;没有g时,只对第一次出现的匹配进行替换 |
p | 打印pattern space中的命令,经常和-n搭配使用 |
Pattern Space和Hold Space互相操作命令总结
命令 | 说明 |
---|---|
h | 将当前Pattern Space中的内容复制到Hold Space,Hold Space原来的内容被清除 |
H | 将一个换行符 + Pattern Space的内容追加到Hold Space,即使Hold Space为空,H命令也会添加换行符 |
g | 将Hold Space中的内容复制到Pattern Space,Pattern Space中原来的内容被清除 |
G | 将一个换行符 + Hold Space中的内容追加到Pattern Space,如果Hold Space 的内容为空,则相当于只追加了一个换行符 |