Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2075588
  • 博文数量: 354
  • 博客积分: 4955
  • 博客等级: 上校
  • 技术积分: 4579
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-21 11:46
文章分类

全部博文(354)

文章存档

2015年(1)

2013年(4)

2012年(86)

2011年(115)

2010年(67)

2009年(81)

我的朋友

分类:

2009-08-07 15:00:17

近来看到几个不是很常见,但是比较有用的sed例子,都和hold space与pattern space有关,于是对几个例子做了自己认为正确的解释,贴出来与大家共享并请指正,继续讨论

例子一
sed G
在文件每一行下面输出一个空行

CODE:

$ cat foo
11111111111111
22222222222222
33333333333333
44444444444444
55555555555555

$ sed G foo
11111111111111

22222222222222

33333333333333

44444444444444

55555555555555
解释:

sed 中 G 的用法
The G function appends the contents of the holding area to the contents of the pattern space. The former and new contents are separated by a newline. The maximum number of addresses is two.

hold space : 保持空间(或者叫保留空间、缓冲区),初始为空
pattern space :模式空间

在上面的例子中,将为空的hold space附加到文件的每一行后面,所以结果是每一行后面多了一个空行

引申出:
sed '/^$/d;G'
在文件的每一个非空行下面输出一个空行
sed '/^$/d;G;G'
在文件的每一个非空行下面输出两个空行

CODE:

$ cat foo
11111111111111
22222222222222

33333333333333
44444444444444
55555555555555

$ sed '/^$/d;G' foo
11111111111111

22222222222222

33333333333333

44444444444444

55555555555555
注:有时会有一些由空格符或者TAB组成的空行,前面的正则式 ^$ 就不能匹配到这样的行,则可以这样
sed '/[[]]/d;G'


例子二
sed '/regex/{x;p;x;}'
在匹配regex的所有行前面插入一个空行

CODE:

$ cat foo
11111111111111
22222222222222
test33333333333333
44444444444444
55555555555555

$ sed '/test/{x;p;x;}' foo
11111111111111
22222222222222

test33333333333333
44444444444444
55555555555555
解释:
sed 中 x 的用法
The exchange function interchanges the contents of the pattern space and the holding area. The maximum number of addresses is two.
即交换保持空间hold space和模式空间pattern space的内容

sed 中 p 的作用是把模式空间复制到标准输出。

分析一下该命令执行过程中保持空间和模式空间的内容

命令 保持空间 模式空间
x 执行前:null 执行后:test\n 执行前:test\n 执行后:null
p 执行前:null 执行后:test\n 执行前:test\n 执行后:null 输出一个空行
x 执行前:test\n 执行后:null 执行前:null 执行后:test\n

(注:把test所在的行简写为test了)

引申:
可以试验一下 sed '/test/{x;p;}' foo 或者 sed '/test/{p;x;}' foo 等,看看结果,体会两个空间的变化

相应的:
sed '/regex/G' 是在匹配regex的所有行下面输出一个空行
sed '/regex/{x;p;x;G;}' 是在匹配regex的所有行前面和下面都输出一个空行


例子三
sed 'n;G;'
在文件的偶数行下面插入一个空行

CODE:

$ cat foo
11111111111111
22222222222222
33333333333333
44444444444444
55555555555555

$ sed 'n;G;' foo
11111111111111
22222222222222

33333333333333
44444444444444

55555555555555
解释:
sed 中 n 的用法:将模式空间拷贝于标准输出。用输入的下一行替换模式空间。

执行 n 以后将第一行输出到标准输出以后,然后第二行进入模式空间,根据前面对 G 的解释,会在第二行后面插入一个空行,然后输出;再执行 n 将第三行输出到标准输出,然后第四行进入模式空间,并插入空行,依此类推

相应的:
sed 'n;n;G' 表示在文件的第 3,6,9,12,... 行后面插入一个空行
sed 'n;n;n;G' 表示在文件的第 4,8,12,16,... 行后面插入一个空行
sed 'n;d' 表示删除文件的偶数行


例子四
sed '$!N;$!D'
输出文件最后2行,相当于 tail -2 foo

CODE:

$ cat foo
11111111111111
22222222222222
33333333333333
44444444444444
55555555555555

$ sed '$!N;$!D' foo
44444444444444
55555555555555
解释:

D 删除模式空间内第一个 newline 字母 \n 前的资料。
N 把输入的下一行添加到模式空间中。

sed '$!N;$!D' : 对文件倒数第二行以前的行来说,N 将当前行的下一行放到模式空间中以后,D 就将模式空间的内容删除了;到倒数第二行的时候,将最后一行附加到倒数第二行下面,然后最后一行不执行 D ,所以文件的最后两行都保存下来了。


还有 N 的另外一种用法

CODE:

$ sed = foo | sed N
1
11111111111111
2
22222222222222
3
33333333333333
4
44444444444444
5
55555555555555

$ sed = foo | sed 'N;s/\n/ /'
1 11111111111111
2 22222222222222
3 33333333333333
4 44444444444444
5 55555555555555
解释:
N 的作用是加上行号,可以用于格式化输出文件


例子五
sed '1!G;h;$!d'
sed -n '1!G;h;$p'
将文件的行反序显示,相当于 tac 命令(有些平台没有这个命令)

CODE:

$ cat foo
11111111111111
22222222222222
33333333333333

$ sed '1!G;h;$!d' foo
33333333333333
22222222222222
11111111111111

$ sed -n '1!G;h;$p' foo
33333333333333
22222222222222
11111111111111
解释:
sed 中 h 用法:h
The h (hold) function copies the contents of the pattern space into a holding area, destroying any previous contents of the holding area.
意思是将模式空间的内容保存到保持空间中去

sed 中的 d 表示删除模式空间。

1!G表示除了第一行以外,其余行都执行G命令;$!d表示除了最后一行以外,其余行都执行d命令。

看一下sed '1!G;h;$!d'命令执行过程中保持空间与模式空间的变化:

命令 保持空间 模式空间
第一行 h;d 执行前:null 执行后:1111\n 执行前:1111\n 执行后:null
第二行 G;h;d 执行前:1111 执行后:2222\n1111\n 执行前:2222\n 执行后:null
第二行 G;h 执行前:2222\1111\n 执行后:3333\n2222\n\1111\n 执行前:3333\n 执行后:3333\n2222\n\1111\n

(注:把各个行简写了)

这样输出以后就是文件的反序了。

题外话:在vi中对一个文件进行反序显示的命令是 :g/./m0 , 意思是按照文件正常顺序每找到一行,就把该行放到文件的最上面一行去,这样循环一下正好把文件的行反序显示了。


# sed 中y的用法

例子
$ sed 'y/12345/ABCDE/' foo
AAAAAAA
BBBBBBB
CCCCCCC
DDDDDDD
EEEEEEE
说明:
将文件foo中的 1 换成 A
将文件foo中的 2 换成 B
将文件foo中的 3 换成 C
将文件foo中的 4 换成 D
将文件foo中的 5 换成 E

注意变换关系是按两个list的位置对应变换,y是一个管局命令,拒绝使用后缀



# sed中D,N,G的执行说明
如果sed中含有D,则重复循环执行D之前的所有函数(包括D),直到D循环结束才执行D之后
函数,所以在D之后的函数只执行一次.
在执行N函数时,如果pattern space为NULL, 则读入两行数据, 如果pattern space已存在
一行数据,则只补充一行数据.
在一次循环中不能既执行D(G)又执行G(D),如果先执行了D就不能执行G.

例子1
-------------------------
$ cat demon
11
22
33
44
55
66
77
-------------------------
$ sed 'N;x;$!D;G' demon
44
66
55
77
-------------------------

下面我们来看循环过程中hold space和pattern space的内容变化
循环 函数 hold space pattern space

第一次 N x D 执行前:null 执行x:11\n22\n 执行N:11\n22\n 执行x:null 执行D:null
第二次 N x D 执行前:11\n22\n 执行x:33\n44\n 执行N:33\n44\n 执行x:11\n22\n 执行D:22\n
第三次 N x D 执行前:33\n44\n 执行x:22\n55\n 执行N:22\n55\n 执行x:33\n44\n 执行D:44\n
第四次 N x D 执行前:22\n55\n 执行x:44\n66\n 执行N:44\n66\n 执行x:22\n55\n 执行D:55\n
最后次 N x G 执行前:44\n66\n 执行x:55\n77\n 执行N:55\n77\n 执行x:44\n66\n 执行G:44\n66\n55\n77\n
(因为sed中含有D,所以前四次循环只执行到D就重复.而最后一次循环中没有D,所以G得以执 行.前两次循环
pattern space都为空所以读入两行数据,后三次都存在一条记录,所以只读入一行.)



例子2
------------------------------
$ sed 'N;x;D;G' demon
66
------------------------------

例子
------------------------------
$ sed 'N;x;D' demon
66
------------------------------

例子2和3的执行结果一样是因为在整个循环中都执行D,所以G被屏蔽掉.



# sed中s的用法
格式: sed 's/regexpr/replacement-pattern/[gn]' filename
作用: s选项通知sed这是一个替换操作, 并查询regexpr,
成功后用replacement-pattern替换它.

例子1
替换每行第一个匹配(sed 's/regexpr/replacement-pattern/1' filename)
-------------------------------------------
sed 's/5/五/' foo
1111111
2222222
3333333
4444444
五555555
6666666
7777777
-------------------------------------------

例子2
替换每行第n个匹配( sed "s/regexpr/replacement-pattern/${n}" filename )
-------------------------------------------
$ n=3
$ sed "s/4/四/${n}" foo
1111111
2222222
3333333
44四4444
5555555
6666666
7777777
-------------------------------------------

例子3
替换每行所有匹配( sed "s/regexpr/replacement-pattern/g" filename )

-------------------------------------------
$ sed "s/4/四/g" foo
1111111
2222222
3333333
四四四四四四四
5555555
6666666
7777777
-------------------------------------------


# sed中的行号处理
例子1
为文件加行号
----------------------------------
$ cat demo
11111
22222

33333

44444
----------------------------------
$ sed = demo | sed 'N;s/\n/:/'
1:11111
2:22222
3:
4:33333
5:
6:44444
----------------------------------

例子2
仅为文件中的正文行加行号
-------------------------------------
$ sed /./= demo | sed '/./N;s/\n/:/'
1:11111
2:22222

4:33333

6:44444
-------------------------------------


#sed中的字串逆向输出
例子
-------------------------------------
$ echo 1234567890|sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
0987654321
-------------------------------------


# sed中的选择性输出
例子1
打印文档奇数行
-------------------------------------
$ sed -n 'p;n' foo
1111111
3333333
5555555
7777777
-------------------------------------

例子2
打印文档偶数行
-------------------------------------
$ sed -n 'n;p' foo
2222222
4444444
6666666
-------------------------------------

例子3
删除连续重复行(大量使用了pattern space 文件太大时要注意;使用 $!N
要当心内存溢出)
-------------------------------------
$ cat demo
11111
22222
22222
33333
44444
44444
-------------------------------------
$ sed '$!N;/^\(.*\)\n\1$/!P;D' demo
11111
22222
33333
44444
-------------------------------------

例子4
合并上下行并以空格相分隔
-------------------------------------
$ cat demo
11111
22222
-------------------------------------
$ sed '$!N;s/\n/ /' demo
11111 22222
-------------------------------------

例子5
将以\符号结尾的行与下行合并并以空格分隔(拼接断行)
-------------------------------------
$ cat demo
1 11111\
2 22222
3 33333\
4 44444
-------------------------------------
$ sed -e :a -e '/\\$/N;s/\\\n/ /; ta' demo
1 11111 2 22222
3 33333 4 44444
-------------------------------------

例子6
按关键字拼接行(如果某行以=开始,则合并到上一行并以空格替代=)
-------------------------------------
$ cat demo
11111
=2222
33333
-------------------------------------
$ sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' demo
11111 2222
33333
-------------------------------------

例子7
删除文档中某标志区域内的关键字匹配行
删除文档中从being开到end结束的块中包含myword的行
-------------------------------------
$ cat demo
myword
begin
myword
Number!
myword
Number!
myword
Number!
myword
Number!
end
myword
Number!
-------------------------------------
$ sed '/^begin/,/^end/{/myword/d;}' demo
myword
begin
Number!
Number!
Number!
Number!
end
myword
Number!
-------------------------------------


# sed中的字串解析

例子1
从字串中解析出两个子串(前2各字符和后9个字符)
--------------------------------------
$ echo "WeLoveChinaUnix"|sed 's/^\(..\).*\(.\{5\}\)\(.\{4\}\)$/\1 \2 \3/'
We China Unix
--------------------------------------
注: 命令行中的 \1 是用来指代前面的 \(..\)
\2 是用来指代前面的 \(.\{5\}\)
\3 是用来指代前面的 \(.\{4\}\)
阅读(640) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~