原文地址:
虽然在CU-Shell版置顶帖里上传了很多关于sed和awk的经典书籍:
不过很惭愧,自己没看过几本,倒不是因为不想看,实际上工作中全然用不到这些高级用法,一个原则,能干活就行……
不过现在看来,这样是不行滴,至少坛子里的很多问题都帮不上忙,对自己的提高也是一种滞后……
这样就引出了这篇帖子的主题,这个问题是之前在浏览“白云苍狗”兄的旧帖子里,看到一个sed的回复而引申出来的:
以下是一些简单的理解,虽然对于高手来说很简单,但是对于刚接触sed的新同学来说,还是有点抽象的,我也是新手,所以哪里有分析的不对或者不到位的,请大家帮忙指正出来!
这里主要是对于sed多行模式空间的N P D操作,先贴上代码:
-
xiabao@6P9SN2X ~$ cat urfile
-
#
-
1
-
2
-
3xiabao@6P9SN2X ~$ sed -r ':a;N;/#/!s/\n/ /;ta;P;D' urfile
-
#
-
1 2 3
-
xiabao@6P9SN2X ~$ sed -rn ':a;N;/#/!s/\n/ /;ta;P;D' urfile
-
#
-
-
xiabao@6P9SN2X ~$ sed -r ':a;$!N;/#/!s/\n/ /;ta;P;D' urfile
-
#
-
1 2 3
-
xiabao@6P9SN2X ~$ sed -rn ':a;$!N;/#/!s/\n/ /;ta;P;D' urfile
-
#
-
1 2 3
再贴上N P D的解释:
P:Print up to the first embedded newline of the current pattern space.
(就是输出模式空间开头到第一个\n之间的内容)
D:If pattern space contains no newline, start a normal new cycle as if the d command was issued. Otherwise, delete text in the pattern space up to the first newline, and restart cycle with the resultant pattern space, without reading a new line of input.
(是删除模式空间开头到第一个\n(含)之间的内容,并且控制流跳到脚本的第一条语句。这里一定要注意这句话“and restart cycle with the resultant pattern space, without reading a new line of input.”,即它是在不改变当前行号的情况下,从头执行的。)
这句话也充分的说明了,为什么很多人不愿意读中文翻译版书籍的原因。:-)
N:Add a newline to the pattern space, then append the next line of input to the pattern space. If there is no more input then sed exits without processing any more commands.
(追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。如果没有下一个可处理的行,则退出)
以下是我的分析(这里就以sed -r ':a;$!N;/#/!s/\n/ /;ta;P;D' urfile为例):
大致可以拆分为3个阶段:
#
1
2
3
#\n1
2\n3
分析:
1. (经过N处理过的输出和原文件没有区别,但是本质是不一样的,我这里为了方便表述,把隐藏的\n写到了同一行)
2. (读入第一个pattern space /#/,$!成立,执行N命令,创建多行模式空间,结果如上所示)
3. (紧接着,读入pattern space /#\n1/,/#/!条件不成立,不执行s/\n//,跳过ta,执行P,打印”#“,执行D,删除"#\n",pattern space内容为/1/)
4. (随后,读入pattern space /1\n2/,/#/!条件成立,执行s/\n//,跳转到:a,进入循环,pattern space内容为/1 2/)
-->
#
1 2\n3
分析:
1. (注意,这里的#的输出是P和D作用的结果,参照第一步)
2. (因为D命令执行成功后会使得控制流跳到脚本的第一条语句,这里,也即跳到了:a处,也即进入了一个新的循环)
3. (新的循环开始,从:a开始执行。注意:不是读入下一行开始,从:a开始执行,所以当前的行号是2,也就说$!永远成立,这也就说明了N前面加不加$!都是可以,效果一样。)
->
#
1 2 3
分析:
(这
里之所以输出1 2
3,不是因为执行了后面的P和D,而是因为当s/\n//执行成功后跳转到了标签a处,又因为N没有下一行可读了,所以就exit了,不再执行后面的命令
(这里说明退出循环是N的作用),这时候pattern space的内容是/1 2
3/,因此就被输出到了标准输出上。(这也间接说明了加了-n后1 2 3就被抑制输出了))
完毕……
|
阅读(860) | 评论(0) | 转发(0) |