虽然后者看上去代码更优化,但事实上采用的是前者。要证明这一点不太容易,好在我想出了下面的方法来证明。下面的示例中使用的是"N",它和"n"在判断逻辑上的行为是一致的。
[root@linuxidc ~]# echo -e "abc\ndef\nxyz" | sed '/def/{a\
haha
;N}'
abc
haha
def
xyz
[root@linuxidc ~]# echo -e "abc\ndef" | sed '/def/{a\
haha
;N}'
abc
def
haha
在以上两个命令中,第一个命令"haha"是插入在匹配行"def"的前面,而第二个命令则是插入在"def"的后面。似乎根据"a"命令的作用来说,第二个命令才是意料之中的结果。
首先,解释第一个命令为何"haha"会出现在匹配行"def"的前面。当sed读取的行能匹配"def"时,将队列化"haha"到内存中,并在有输出流的时候追加到输出流尾部。由于这里的输出流来自于"a"命令后的"N"命令,该命令将模式空间锁住,使得隐含动作自动输出的内容为空,但队列化的内容还是发现了这个空输出流,于是追加在这个空流的尾部。再之后,"N"将下一行读取到模式空间中,到了SCRIPT循环的结尾,再次自动输出,此时模式空间有两行:"def" 和 "xyz",这两行同时被输出。显然,在"def"被输出之前,队列化的内容已经随着空输出流而输出了。
再解释为何第二个命令的结果中"haha"在"def"之后,这也是待证明的疑问。第二个命令中,由于"def"已经是输入流的最后一行,"N"已经无法再读取下一行,于是输出当前模式空间内容并退出sed程序。假设,"n"或"N"命令是先自动输出、清空模式空间内容,再判断是否有下一行可读取的,那么在判断之前自动输出时,"N"不知道是否还有下一行,于是队列化的内容应该同第一个命令一样,插入在"def"之前。但结果却并非如此。如果先判断是否有下一行可供读取,再输出、清空模式空间,则队列化内容是跟随着"N"退出sed程序前输出的,这正符合第二个命令的结果。