转自http://www.360doc.com/content/13/0220/18/8547696_266798284.shtml
awk于1977年出生,今年36岁本命年,sed比awk大2-3岁,awk就像林妹妹,sed就是宝玉哥哥了。所以 林妹妹跳了个Topless,他的哥哥sed坐不住了,也一定要出来抖一抖。
sed全名叫stream editor,流编辑器,用程序的方式来编辑文本,相当的hacker啊。sed基本上就是玩正则模式匹配,所以,玩sed的人,正则表达式一般都比较强。
同样,本篇文章不会说sed的全部东西,你可以参看sed的手册,我这里主要还是想和大家竞争一下那些从手机指缝间或马桶里流走的时间,用这些时间来学习一些东西。当然,接下来的还是要靠大家自己双手。
用s命令替换
我使用下面的这段文本做演示:
1
2
3
4
5
6
7
8
9
|
$ cat pets.txt This cat my cat 's This my This my This my |
把其中的my字符串替换成Hao Chen’s,下面的语句应该很好理解(s表示替换命令,/my/表示匹配my,/Hao Chen’s/表示把匹配替换成Hao Chen’s,/g 表示一行上的替换所有的匹配):
1
2
3
4
5
6
7
8
9
|
$ sed "s/my/Hao
This cat Hao 's s This Hao 's s This Hao 's s This Hao 's s |
注意:如果你要使用单引号,那么你没办法通过\’这样来转义,就有双引号就可以了,在双引号内可以用\”来转义。
再注意:上面的sed并没有对文件的内容改变,只是把处理过后的内容输出,如果你要写回文件,你可以使用重定向,如:
1
|
$ sed "s/my/Hao
|
或使用 -i 参数直接修改文件内容:
1
|
$ sed -i "s/my/Hao
|
在每一行最前面加点东西:
1
2
3
4
5
6
7
8
9
|
$ sed 's/^/#/g'
#This # #This # #This # #This # |
在每一行最后面加点东西:
1
2
3
4
5
6
7
8
9
|
$ sed 's/$/
This cat --- my cat 's This my This my This my |
顺手介绍一下正则表达式的一些最基本的东西:
- ^ 表示一行的开头。如:/^#/ 以#开头的匹配。
- $ 表示一行的结尾。如:/}$/ 以}结尾的匹配
- \< 表示词首。 如 \ 表示词尾。 如 abc\> 表示以 abc 結尾的詞.
- . 表示任何单个字符。
- * 表示某个字符出现了0次或多次。
- [ ] 字符集合。 如:[abc]表示匹配a或b或c,还有[a-zA-Z]表示匹配所有的26个字符。如果其中有^表示反,如[^a]表示非a的字符
正规则表达式是一些很牛的事,比如我们要去掉某html中的tags:
1
|
< b >This</ b > span style = "text-decoration: >I</ span > |
看看我们的sed命令
1
2
3
4
5
6
7
8
|
# $ sed 's/<.*>//g'
Understand? # # $ sed 's/<[^>]*>//g'
This |
我们再来看看指定需要替换的内容:
1
2
3
4
5
6
7
8
9
|
$ sed "3s/my/your/g"
This cat my cat 's This my This my This my |
下面的命令只替换第3到第6行的文本。
1
2
3
4
5
6
7
8
9
|
$ sed "3,6s/my/your/g"
This cat my cat 's This your This your This my |
1
2
3
4
5
|
$ cat my.txt This cat , cat 's This This This |
只替换每一行的第一个s:
1
2
3
4
5
|
$ sed 's/s/S/1'
ThiS cat , cat 's ThiS ThiS ThiS |
只替换每一行的第二个s:
1
2
3
4
5
|
$ sed 's/s/S/2'
This cat , cat 's This This This |
只替换第一行的第3个以后的s:
1
2
3
4
5
|
$ sed 's/s/S/3g'
This cat , cat 'S This This This |
多个匹配
如果我们需要一次替换多个模式,可参看下面的示例:(第一个模式把第一行到第三行的my替换成your,第二个则把第3行以后的This替换成了That)
1
2
3
4
5
|
$ sed '1,3s/my/your/g;
This cat , cat 's This That That |
上面的命令等价于:(注:下面使用的是sed的-e命令行参数)
1
|
sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' my.txt |
我们可以使用&来当做被匹配的变量,然后可以在基本左右加点东西。如下所示:
1
2
3
4
5
|
$ sed 's/my/[&]/g'
This cat , cat 's This This This |
圆括号匹配
使用圆括号匹配的示例:(圆括号括起来的正则表达式所匹配的字符串会可以当成变量来使用,sed中使用的是\1,\2…)
1
2
3
4
5
|
$ sed 's/This
cat :betty dog:frank fish:george goat:adam |
上面这个例子中的正则表达式有点复杂,解开如下(去掉转义字符):
正则为:This is my ([^,]*),.*is (.*)
匹配为:This is my (cat),……….is (betty)
然后:\1就是cat,\2就是betty
sed的命令
让我们回到最一开始的例子pets.txt,让我们来看几个命令:
N命令
先来看N命令 —— 把下一行的内容纳入当成缓冲区做匹配。
下面的的示例会把原文本中的偶数行纳入奇数行匹配,而s只匹配并替换一次,所以,就成了下面的结果:
1
2
3
4
5
6
7
8
9
|
$ sed 'N;s/my/your/'
This cat my cat 's This my This my This my |
也就是说,原来的文件成了:
1
2
3
4
|
This cat \n cat 's This This This |
这样一来,下面的例子你就明白了,
1
2
3
4
5
|
$ sed 'N;s/\n/,/'
This cat , cat 's This This This |
a命令和i命令
a命令就是append, i命令就是insert,它们是用来添加行的。如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# $ sed "1
This This cat , cat 's This This This # $ sed "$
This cat , cat 's This This This This |
我们可以运用匹配来添加文本:
1
2
3
4
5
6
7
|
# $ sed "/fish/a
This cat , cat 's This This This This |
下面这个例子是对每一行都挺插入:
1
2
3
4
5
6
7
8
9
|
$ sed "/my/a
This cat , cat 's ---- This ---- This ---- This ---- |
c命令
c 命令是替换匹配行
1
2
3
4
5
6
7
8
9
10
11
|
$ sed "2
This cat , cat 's This This This $ sed "/fish/c
This cat , cat 's This This This |
d命令
删除匹配行
1
2
3
4
5
6
7
8
9
10
11
12
|
$ sed '/fish/d'
This cat , cat 's This This $ sed '2d'
This cat , cat 's This This $ sed '2,$d'
This cat , cat 's |
p命令
打印命令
你可以把这个命令当成grep式的命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# # $ sed '/fish/p'
This cat , cat 's This This This This # $ sed -n '/fish/p' my.txt This # $ sed -n '/dog/,/fish/p' my.txt This This #从第一行打印到匹配fish成功的那一行 $ sed -n '1,/fish/p' my.txt This cat , cat 's This This |
几个知识点
好了,下面我们要介绍四个sed的基本知识点:
Pattern Space
第零个是关于-n参数的,大家也许没看懂,没关系,我们来看一下sed处理文本的伪代码,并了解一下Pattern Space的概念:
1
2
3
4
5
6
7
8
9
10
11
12
|
foreach //放入把行Pattern_Space Pattern_Space // Pattern_Space // if (sed "-n" ) print } } |
Address
第一个是关于address,几乎上述所有的命令都是这样的(注:其中的!表示匹配成功后是否执行命令)
[address[,address]][!]{cmd}
address可以是一个数字,也可以是一个模式,你可以通过逗号要分隔两个address 表示两个address的区间,参执行命令cmd,伪代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
bool bexec false foreach if ( bexec true ; } if ( true ) EXEC(sed_cmd); } if ( bexec false ; } } |
关于address可以使用相对位置,如:
1
2
3
4
5
6
7
8
9
10
|
# $ sed '/dog/,+3s/^/#
This cat my cat 's # # # # This my |
命令打包
第二个是cmd可以是多个,它们可以用分号分开,可以用大括号括起来作为嵌套命令。下面是几个例子:
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
|
$ cat pets.txt This cat my cat 's This my This my This my # $ sed '3,6
This cat my cat 's my my This my # $ sed '3,6
This cat my cat 's This my my This my # $ sed '1,${/This/d;s/^
my cat 's my my my |
Hold Space
第三个我们再来看一下 Hold Space
接下来,我们需要了解一下Hold Space的概念,我们先来看四个命令:
g: 将hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
G: 将hold space中的内容append到pattern space\n后
h: 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
H: 将pattern space中的内容append到hold space\n后
x: 交换pattern space和hold space的内容
这些命令有什么用?我们来看两个示例吧,用到的示例文件是:
1
2
3
4
|
$ cat t.txt one two three |
第一个示例:
1
2
3
4
5
6
7
8
9
|
$ sed 'H;g'
one one two one two three |
是不是有点没看懂,我作个图你就看懂了。
第二个示例,反序了一个文件的行:
1
2
3
4
|
$ sed '1!G;h;$!d'
three two one |
其中的 ’1!G;h;$!d’ 可拆解为三个命令
- 1!G —— 只有第一行不执行G命令,将hold space中的内容append回到pattern space
- h —— 第一行都执行h命令,将pattern space中的内容拷贝到hold space中
- $!d —— 除了最后一行不执行d命令,其它行都执行d命令,删除当前行
这个执行序列很难理解,做个图如下大家就明白了:
就先说这么多吧,希望对大家有用。
(全文完)