Chinaunix

标题: sed N P D 彻底讲解 [打印本页]

作者: expert1    时间: 2019-02-02 10:31
标题: sed N P D 彻底讲解
本帖最后由 expert1 于 2019-02-13 16:20 编辑

N年前研究过这个,忘了做笔记,真是好记性不如烂笔头。 最近又遇到而且想起了这个问题。简单分享和探讨下,如果有不对之处,欢迎批评指正。
注意,以下需要对sed的工作模式,包括pattern space有一定的理解。

1. 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.


简单说,N加一个\n, 然后追加下一行到当前的pattern space, 如果没有下一行,退出。 这也隐含了一个事实: N会改变input的行号
---------------


       P      Print up to the first embedded newline of the current pattern space.

P 打印pattern 第一个\n(包括\n)的内容。

------


一个例子:
  1. seq 5 | sed -n 'N;P'
复制代码
1
3

debug一下pattern space,可见N改变了输入行号。
  1. seq 5 |sed -n 'l;N;P'
复制代码



分析,读入1,N追加,此时pattern space是1\n2,P打印1\n,输出1, 注意此时input变成了3(也就是到了第三行。如果没有N,此时应该是第2行。),然后是3\n4,打印3。此时Input是5,由于 no more input, 此时退出,后面的P也不执行了。虽然此时pattern space是5,但由于 -n 抑制了自动打印。所以最终结果是
1
3
# 可见N在没有input的时候,会自动退出sed 工作流程,之后的都不再执行了。

----------------------------------------------------

下面再说一下最不容易理解的D


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.
从解释看,D在pattern space没有\n(只有用了N,才有\n,除非你特殊替换等)的情况下,和d一样都是删掉pattern space的内容,然后跳到命令的开头(这里的跳到开头在下面解释),并且读入下一行再处理(正常的工作cycle就是这样)。

Otherwise,也就是pattern space有内容(大多数情况下是用了N),把pattern space的第一个\n之前的内容删掉,然后继续跳到开头循环,不读入下一行。

  1. seq 9 | sed 'N;D;P'
复制代码
9

1读入2,pattern space是1\n2, contains newline了,D删掉1\n, 然后继续跳到开头(构成了循环),也就是最开始的地方, 继续N,此时pattern space是2\n3, 删掉2\n, 以此类推。最后8\n9,删掉8\n, pattern space是9,由于N 不满足(没有内容可以输入了),退出。可见,D后面的P完全不起作用,D构成了一个循环。

结果9 是由于pattern space是9, 又没有-n 抑制自动打印pattern space,所以得到的9

without reading a new line of input, 这个做什么的呢? 比如说1\n2,按照正常情况下,下一个Input应该是3了(
  1. sed -n 'N;P;D'
复制代码

), 但D不再读取input了,直接跳到开头,所以必须有N来负责读入下一行,此时pattern space的内容是2, 就着这个pattern space,跳到命令的开头,也就是N,这样就是2\n3了,可以对比一下,有D和无D的时候,pattern space的内容一看就知道了。


------------------------------------------------
另外一个例子,可以清晰的看到D,如果没有N,而pattern space又有内容的话,下一行永远不会被处理。
  1. seq 5 | sed 's/^/hello\n/;p; D'
复制代码

这个是个无限的循环,第一次,hello\n1, 然后p打印,D删掉hello\n, 然后循环,再替换,再打印,再D。就是2永远没有机会处理。


综合以上,我们发现,D多数情况情况下,必须跟在N后面,不然的话下一行是不会读入的,成了循环。而P,必须在D前面,不然没机会P(D构成了循环,直到pattern space没东西,才轮到P)。

他们的顺序是 N P D

也就是N追加,P打印需要的,D删掉,继续循环(由D构成的循环,也就是restart  cycle)。

最后,一个例子来学习一下,假设以下是学习成绩,要变成
tom 99 ..
jerry ...

  1. 那么 sed ':a;N;/\n[A-Za-z]/!s/\n/ /;ta;P;D'
复制代码

# file
tom
99
86
92
jerry
96
87

----------
最后 对比,加了D,由于每次循环到N,等于是逐行处理了。
  1. seq 5 |sed -n 'l;N;P;D'
  2. 1$
  3. 1
  4. 2$
  5. 2
  6. 3$
  7. 3
  8. 4$
  9. 4
  10. 5$
复制代码






作者: seesea2517    时间: 2019-02-02 10:59
大过年的还在更新,赶紧来顶顶。
作者: ll104567    时间: 2019-02-02 11:05
好贴要顶= =,好久不用sed了
作者: waker    时间: 2019-02-04 15:01
牛!学习了!
作者: 86808801    时间: 2019-02-10 15:50
好像是什么空间模式。。
作者: 86808801    时间: 2019-02-10 15:50
好像是什么空间模式。。
作者: cjaizss    时间: 2019-02-11 15:25
本帖最后由 cjaizss 于 2019-02-13 12:37 编辑

套神威武Spirit Tom Tall Big Up, b/c he is the No. 1 spirit w/o any explaination.
向套神致敬!



作者: yinyuemi    时间: 2019-02-13 11:40
母神v5,牛,学习了!
作者: zooyo    时间: 2019-02-13 11:45
提示: 作者被禁止或删除 内容自动屏蔽
作者: 惟吾无为    时间: 2019-02-13 11:49
专程绑定手机号登陆膜拜!
作者: zooyo    时间: 2019-02-13 11:50
提示: 作者被禁止或删除 内容自动屏蔽
作者: reyleon    时间: 2019-02-13 14:39
厉害了我的哥!
作者: expert1    时间: 2019-02-16 12:17
d跟D差不多也是循环,不过它是读入下一行(start a new cycle),seq 10 | sed 'd;p' 则这里的p不会执行,d删除,读入下一行,以此类推。

而label的t/T/b的时候,跟D差不多,也是保留现有的pattern space,不删除,然后跳到label处。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2