对一个sed"N;P;D"多行模式处理语句的分析

虽然在CU-Shell版置顶帖里上传了很多关于sed和awk的经典书籍:

http://bbs.chinaunix.net/thread-1776727-1-1.html

不过很惭愧,自己没看过几本,倒不是因为不想看,实际上工作中全然用不到这些高级用法,一个原则,能干活就行……

不过现在看来,这样是不行滴,至少坛子里的很多问题都帮不上忙,对自己的提高也是一种滞后……

这样就引出了这篇帖子的主题,这个问题是之前在浏览“白云苍狗”兄的旧帖子里,看到一个sed的回复而引申出来的:http://bbs.chinaunix.net/redirec ... 1354674&pid=9947995

以下是一些简单的理解,虽然对于高手来说很简单,但是对于刚接触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就被抑制输出了))

完毕……

补充:
最后,贴上sedsed调试信息:

xiabao@6P9SN2X ~
$ cat npd
:a;$!N;/#/!s/\n/ /;ta;P;D xiabao@6P9SN2X ~
$ cat urfile | sedsed -d -f npd
PATT:#$
HOLD:$
COMM::a
COMM:$ !N
PATT:#\n1$
HOLD:$
COMM:/# / !s/ \n / /
PATT:#\n1$
HOLD:$
COMM:t a
COMM:P
#
PATT:#\n1$
HOLD:$
COMM:D
PATT:1$
HOLD:$
COMM::a
COMM:$ !N
PATT:1\n2$
HOLD:$
COMM:/# / !s/ \n / /
PATT:1 2$
HOLD:$
COMM:t a
COMM:$ !N
PATT:1 2\n3$
HOLD:$
COMM:/# / !s/ \n / /
PATT:1 2 3$
HOLD:$
COMM:t a
COMM:$ !N
PATT:1 2 3$
HOLD:$
COMM:/# / !s/ \n / /
PATT:1 2 3$
HOLD:$
COMM:t a
COMM:P
1 2 3
PATT:1 2 3$
HOLD:$
COMM:D

从sedsed的调试信息就可以很清楚地看出了整个语句的执行过程。


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值