分页: 1 / 1

遇到一段奇怪的sed代码

发表于 : 2012-01-08 14:01
mafn
有一个文本如下:
$ cat expl.6
I want to see @fl(what will happen) if we put the
font change commands @fl(on a set of lines). If I understand
things (correctly), the @fl(third) line causes problems. (No?).
Is this really the case, or is it (maybe) just something else?

Let's test having two on a line @fl(here) and @fl(there) as
well as one that begins on one line and ends @fl(somewhere
on another line). What if @fl(it is here) on the line?
Another @fl(one).

现在要作的就是将"fl@(…)替换为"\fB(…)\fR。以下就是满足条件的sed命令:
$ sed 's/@fl(\([^)]*\))/\\fB\1\\fR/g
> /@fl(.*/{
> N
> s/@fl(\(.*\n[^)]*\))/\\fB\1\\fR/g
> P
> D
> }' expl.6
然而,如果不使用这种输入输出循环,而是单单用N来实现的话,就会出现问题:
$ sed 's/@fl(\([^)]*\))/\\fB\1\\fR/g
> /@fl(.*/{
> N
> s/@fl(\(.*\n[^)]*\))/\\fB\1\\fR/g
> }' expl.6

我运行了两段代码,发现第二段代码的问题出在文本倒数第二行的@fl(it is here)没有被替换。文本前六行都没有触发程序第二行。到第七行时触发程序第二行,于是模式空间追加读入文本第八行,进行程序第四行命令的替换,g选项应该会将两个@fl都替换掉,但最后却没有,why?和第一段代码相比,第二段代码只是删去了P和D,加入P和D两个命令怎么就能全部替换?
百思不得其解,劳驾各位大侠指个路。谢谢!

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-08 14:31
MaskRay
第二段代码碰到跨行 @fl 时,要求 s/@fl(\(.*\n[^)]*\))/\\fB\1\\fR/g
而倒数第二行那个没被替换的 @fl() 里面没有 \n

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-08 16:17
eexpress
复杂的sed,以前也搞过。

还是用Perl吧。不蛋疼。

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-08 17:48
josephyoung
原来程序的第7行,它是这样执行的:
首先判断你的第一个正则替换,不成立,没有替换成功;
执行N,读入下一行;
执行第二个正则替换,将那个跨行的f@替换了;
执行P,打印从当前模式空间开头到第一个\n的字符,也就是本来的第7行,打印;
执行D,删除从模式空间开头到第一个\n的字符,也就是删掉原来的第7行(包括\n);
循环回到所有命令的开头并且不读入下一行,这时你模式空间的是刚才删掉第7行后剩下的第8行;
第8行又开始执行第一个正则替换。。。如此继续

你的命令里面没有了D,就没有那个删除和循环,当你的程序替换了第7行的那个跨行的f@()以后,没有命令了,这时sed会抹掉当前模式空间的内容并读入下一行(也就是第9行),然后继续新一轮的执行

注意D的作用有两个,有一个是删除模式空间从开头到第一个\n的所有字符,这个好理解
另一个作用是,不要读入新的一行而又从命令的最开头进行执行,这个初学者往往会不清楚

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-08 20:58
mafn
十分感谢 MaskRay, josephyoung, 两位大侠。
不怕大家见笑,上面这个问题,我上午想了差不多一个小时。呵呵。
首先是自己看走眼了。程序第四行的正则表达式明明不同于第一行的,可是我看了一个小时,竟然没有发现里面的\n!太要命了。
其次对D命令缺乏正确理解。其实不但D,对于N也是,理解不了,往往牵强附会。 josephyoung在四楼的解释非常详细,我想我终于能理解D命令的第二个作用了。
再次感谢两位大侠!

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-08 21:31
fnan
sed -n '1h;2,$H; ${g;s/@fl(\([^)]*\))/\\fB\1\\fR/gp}' expl.6
#简化逻辑。
sed '/@fl([^)]*$/N;s/@fl(\([^)]*\))/\\fB\1\\fR/g;P;D' expl.6
#D指令可以这样用。

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-09 0:42
mafn
fnan, 我还是喜欢第一句,逻辑简化了,功能也强大多了。
谢谢! :em51

Re: 遇到一段奇怪的sed代码

发表于 : 2012-01-09 1:03
fnan
sed 'N;s/@fl(\([^)]*\))/\\fB\1\\fR/g;P;D' expl.6
#还可以再简化。