首先,应该明白模式空间的定义。模式空间就是读入行所在的缓存,sed对文本行进行的处理都是在这个缓存中进行的。这对接下来的学习是有帮助的。 在正常情况下,sed将待处理的行读入模式空间,脚本中的命令就一条接着一条的对该行进行处理,直到脚本执行完毕,然后该行被输出,模式空间清空;然后重复刚才的动作,文件中的新的一行被读入,直到文件处理完备。 但是,各种各样的原因,比如用户希望在某个条件下脚本中的某个命令被执行,或者希望模式空间得到保留以便下一次的处理,都有可能使得sed在处理文件的时候不按照正常的流程来进行。这个时候,sed设置了一些高级命令来满足用户的要求。 总的来说,这些命令可以划分为以下三类: 1. N、D、P:处理多行模式空间的问题; 2. H、h、G、g、x:将模式空间的内容放入存储空间以便接下来的编辑; 3. :、b、t:在脚本中实现分支与条件结构。 多行模式空间的处理: 由于正则表达式是面向行的,因此,如若某个词组一部分位于某行的结尾,另外一部分又在下一行的开始,这个时候用grep等命令来处理就相当的困难。然而,借助于sed的多行命令N、D、P,却可以轻易地完成这个任务。 多行Next(N)命令是相对于next(n)命令的,后者将模式空间中的内容输出,然后把下一行读入模式空间,但是脚本并不会转移到开始而是从当前的n 命令之后开始执行;而前者则保存原来模式空间中的内容,再把新的一行读入,两者之间依靠一个换行符"\n"来分隔。在N命令执行后,控制流将继续用N命令以后的命令对模式空间进行处理。 值得注意的是,在多行模式中,特殊字符"^"和"$"匹配的是模式空间的最开始与最末尾,而不是内嵌"\n"的开始与末尾。 例1: $ cat expl.1 Consult Section 3.1 in the Owner and Operator Guide for a description of the tape drives available on your system. 现在要将"Owner and Operator Guide"替换为"Installation Guide": $ sed '/Operator$/{ > N > s/Owner and Operator\nGuide/Installation Guide\ > / > }' expl.1 在上面的例子中要注意的是,行与行之间存在内嵌的换行符;另外在用于替代的内容中要插入换行符的话,要用如上的"\"的转义。 再看一个例子: 例2: $ cat expl.2 Consult Section 3.1 in the Owner and Operator Guide for a description of the tape drives available on your system.
Look in the Owner and Operator Guide shipped with your system.
Two manuals are provided including the Owner and Operator Guide and the User Guide.
The Owner and Operator Guide is shipped with your system. $ sed 's/Owner and Operator Guide/Installation Guide/ > /Owner/{ > N > s/ *\n/ / > s/Owner and Operator Guide */Installation Guide\ > / }' expl.2 结果得到: Consult Section 3.1 in the Installation Guide for a description of the tape drives available on your system.
Look in the Installation Guide shipped with your system.
Two manuals are provided including the Installation Guide and the User Guide.
The Installation Guide is shipped with your system. 看上去sed命令中作了两次替换是多余的。实际上,如果去掉第一次替换,再运行脚本,就会发现输出存在两个问题。一个是结果中最后一行不会被替换(在某些版本的sed中甚至不会被输出)。这是因为最后一行匹配了"Owner",执行N命令,但是已经到了文件末尾,某些版本就会直接打印这行再退出,而另外一些版本则是不作出打印立即退出。对于这个问题可以通过命令"$!N"来解决。这表示N命令对最后一行不起作用。另外一个问题是"look manuals"一段被拆为两行,而且与下一段的空行被删除了。这是因为内嵌的换行符被替换的结果。因此,sed中做两次替换一点也不是多余的。 例3: $ cat expl.3
This is a test paragraph in Interleaf style ASCII. Another line in a paragr aph. Yet another.
My wife won't let me buy a power saw. She is afraid of an accident if I use one. So I rely on a hand saw for a variety of weekend projects like building shelves. However, if I made my living as a carpenter, I would have to use a power saw. The speed and efficiency provided by power tools would be essential to being productive.
For people who create and modify text files, sed and awk are power tools for editing.
Most of the things that you can do with these programs can be done interactively with a text editor. However, using these programs can save many hours of repetitive work in achieving the same result.
$ sed '/^$/!{ > H > d > } > /^$/{ > x > s/^\n/
/ > s/$/<\/p>/ > G > }' expl.10 运行一下这个命令,看看结果是怎样的。其实结果已经不重要了。通过这个子,应该学会的是脚本中体现的流程控制的思想。脚本的第一部分使用"!"表示对不匹配的行进行处理,但是这种处理因为"d"的存在,不会走脚本的底部,自然也就不会有任何的输出;在脚本的第二部分中,脚本的确是到了最后的,相应的也清除了模式空间和存储空间的内容,为读入下一段做好了准备。
(1) 创建循环: :top command1 command2 /pattern/b top command3 (2) 忽略某些不满足条件的命令: command1 /patern/b end command2 :end command3 (3) 命令的两个部分只能执行其中一个: command1 /pattern/b dothere command b :dothere command3 t命令的格式和b命令是一样的: [address]t[label] 它表示的是如果满足address的话,sed脚本就会根据t命令指示的标签进行流程转移。而标签的规则和上面讲的b命令的规则是一样的。下面也给出一个例子: s/pattern/replacement/ t break command :break 还是用例6的sed脚本为例子。其实仔细思考一下就会发现这个脚本不是足够强大:如果某个@fl结构跨越了两行,比如说三行怎么办?这就需要下面这个加强版的sed了: $ cat expl.6.sed :begin /@fl(\([^)]*\))/{ s//\\fB\1\\fR/g b begin } /@fl(.*/{ N s/@f1(\([^)]*\n[^)]*\))/\\fB\1\\fR/g t again b begin } :again P