Linux centos7 sed之N P D

有一文件passwd2,在用sort+sed命令去重的过程中,用到N P D,这是一个十分有趣的命令,值得分析讨论。

本文重点描述了执行的循环过程。也纠正了一些网上不正确的表述:多行模式空间不是保持空间

cat passwd2

root:x:0:0:root:/root:/bin/bash

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

bin:x:1:1:bin:/bin:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

文件中有多行重复,如何去重呢?主要方法有:sort+uniq方法,awk方法和sort+sed方法。其中,sort+sed方法主要代码:

sort passwd2 |sed  '$!N;/^\(.*\)\n\1$/!P;D'

一、sed工作原理

sed在正常情况下,将处理的行读入“pattern space”(模式空间),脚本中的“sed-command(sed命令)”就一条接着一条进行处理,直到脚本执行完毕。然后该行被输出,(pattern space)模式空间被清空;接着,再重复执行刚才的动作,文件中的新的一行被读入,直到文件处理完毕。

由于种种原因,如果用户希望在某种条件下脚本中的某行在(pattern space)模式空间保留,以便下一次使用,这都有可能使sed在处理文件的时候,不按照正常的流程,这时候就需要用sed高级命令来满足需求,这就用到命令n和命令N。

命令n:读取下一行到pattern space。

由于pattern space中有按照正常流程读取的内容,使用n命令后,pattern space中又有了一行,此时,pattern space中有2行内容,但是先读取的那一行不会被取代、覆盖或删除;当n命令后,还有其他命令的时候,如p,此时打印出的结果是n命令读取的那一行的内容。

命令N:读取下一行到pattern space中,追加到原来行内容的后面。如原来的行内容是line1,下一行内容是line2。执行N命令后,pattern space中内容是:line1\nline2。

为了理解上述概念,我们可以参考如下知识:

单行模式空间

是指模式空间中仅有一行的情况。sed命令使用中,模式空间中仅读入文件的一行、处理一行、输出一行处理结果。

多行模式空间

是指模式空间中具有二行或多行的情况。sed命令使用中,模式空间中只有n和N命令在读入一行数据没有处理的情况下,又读取了另一行的数据。模式空间的多行是逻辑一行,其中包含多个换行符(\n)、实际是物理多行。

二、N P D

sed的众多命令中,n,d,p和N,D,P应用广泛。二者有相同之处,也有重大差别。主要表现在:n,d,p用于单行模式空间,而N,D,P应用于多行模式空间。

n&N

n,next的简写。n命令不创建多行模式空间;N(Next)通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间。简单说,N加一个\n, 然后追加下一行到当前的pattern space, 如果没有下一行,退出。 这也隐含了一个事实: N会改变input的行号。

有且只有N才能创建多行模式空间,才使P、D有了用武之地。

注:在模式空间中嵌入的换行符可以利用转移序列"\n"来匹配,在多行模式空间中"^"匹配多行模式空间中的第一个字条(前一行内容),而不匹配换行符后面的字符(后一行内容),同样"$"只匹配多行模式空间最后的换行符。

d&D

d删除单行模式空间的内容并导致读入新的输入行,并且在脚本顶端重新使用编辑方法。

D删除多行模式空间中第一个字条(前一行内容)。如前面多行模式空间中(line1\nline2)的line1\n,D不会导致读入新的输入行并且它返回到脚本的顶端,将后续指令应用于多行模式空间的剩余内容。

p&P

p 打印单行模式空间的行内容

P打印多行模式空间中(line1\nline2)的line1\n(包括\n)内容,\n换行符是打印不出来的。

N&P&D

P命令经常在N之后和D之前。N&D&P能建立一个输入/输出循环,用来维护多行模式空间,但是一次只输出一行。这个循环的目的是只(P)输出多行模式空间的第一行,然后删除(D)多行模式空间第一行,然后返回到脚本的顶端,将所有的命令应用于模式空间的第二行。

三、语句释义

sort passwd2 |sed  '$!N;/^\(.*\)\n\1$/!P;D'

对文件先排序,再去除重复行。

1.sort passwd2

对文件进行排序,没有什么难度,十分简单的命令。

2.sed  '$!N;/^\(.*\)\n\1$/!P;D'

去除重复行

$! 这个表示当前读入行不是最后一行的意思。$表示是最后一行的意思. !则是取反。也可以理解为,只有最后一行不执行后面的命令

N (当前读入行不是最后一行时)往模式空间中读入一行。使模式空间中有两行数据(创建多行模式空间)

/^\(.*\)\n\1$/!

先看:/^\(.*\)\n\1$/ 这个表示匹配一个pattern。这个pattern是说多行模式空间中的两行(被\n分隔的两行),内容是否相等。实现方法是\n后面的内容用\1来反向引用前面的分组。

综合理解这段代码: 第一行用一个分组(.*)(实际就是任意内容的意思)来表示,然后中间一个\n(就是换行符),最后第二行的内容直接引用第1分组,即两行内容比较,用此判断后面的动作。

最后加了一个叹号’!’,说明要取反,意思是两行内容不同的情况下执行后面的command,即P

P 是打印首行内容的意思  ^\(.*\)\n

最后一个命令是D

D 也是删除首行的意思 ^\(.*\)\n

注意这两个命令都是对多行模式空间的内容进行处理

四、循环剖析

结合前面的sed工作原理,及各项命令的了解,前面的梳理并不能让我们全面了解去重的过程。下面从循环过程,分析一下。

对原文件排序后,前面几行如下:

从上图可知,通过排序,原文件各行顺序都打乱了;重复的行都在一起。

当执行sed命令后,sed首先把标准输入的第一行读入模式空间,因为没有单行模式空间命令,第一行读入后没有任何变化。

 '$!N;/^\(.*\)\n\1$/!P;D'中没有对第一行执行的命令。

第一次读入过程的结果:第一行没有什么输出;第一行内容存放在单行模式空间。

sed开始读取标准输入的第二行到模式空间,构成多行模式空间。

N命令:在第一行后面追加第二行

adm:x:3:4:adm:/var/adm:/sbin/nologin\nadm:x:3:4:adm:/var/adm:/sbin/nologin

/^\(.*\)\n\1$/匹配成功,后面的!P,要求不打印\n及前面的内容^\(.*\)(即第一行内容);最后命令D,删除^\(.*\)(即第一行内容),结束本次读入行过程。

第二次读入过程的结果:第二行没有什么输出;第二行内容存放在多行模式空间中。

接下来,继续读入第三行内容。

因为与第二行内容相同,第三行结束后效果一样。

第三次读入过程的结果:第三行没有什么输出;第三行内容存放在多行模式空间中。

接下来,继续读入第四行内容。

第四行内容追加到第三行后面,如下

adm:x:3:4:adm:/var/adm:/sbin/nologin\n bin:x:1:1:bin:/bin:/sbin/nologin

/^\(.*\)\n\1$/匹配不成功,后面的!P,要求打印\n及前面的内容^\(.*\)(即第三行内容);最后命令D,删除^\(.*\)(即第三行内容),结束本次读入行过程。

第四次读入过程的结果:第四行输出第三行内容(我们知道前三行都一样,最终只输出了一次);第四行内容存放在多行模式空间中。

接下来,继续读入第五行内容。

第五行内容追加到第四行后面,如下

bin:x:1:1:bin:/bin:/sbin/nologin \n daemon:x:2:2:daemon:/sbin:/sbin/nologin

/^\(.*\)\n\1$/匹配不成功,后面的!P,要求打印\n及前面的内容^\(.*\)(即第四行内容);最后命令D,删除^\(.*\)(即第四行内容),结束本次读入行过程。

第五次读入过程的结果:第五行输出第四行内容;第五行内容存放在多行模式空间中。

后面的过程,基本相同,不再一一描述。

主要结论:前后两行相同,没有输出;前后两行不相同,输出前一行的内容

最后一行读入标准输入:

根据N命令的特点,最后一行是前一行(倒数第二行)的N对象。当时就读入了最后一行且比较了最后两行是否相等,由比较结果处理了倒数第二行到底打印?删除?

当没有下一行时,sed执行到最后一行,由于没有两行,因此“两行不相等”的条件仍然满足,所以最后一行也会原样输出!!

最后的D命令,删除模式空间内容,最终退出sed进程。

最后一次读入过程的结果:输出模式空间内存放的内容(最后一行内容)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_36142959

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值