sed高级命令
高级命令分成了3个组:
- 处理了多行模式空间(N、D、P)。
- 采用保持空间来保存模式空间的内容并使它可用于后续的命令(H、h、G、g、x) 。 编写使用分支
- 和条件指令的脚本来更改控制流(:、b、 t)。
多行模式空间
在前面正则表达式的讨论中,我们强调模式匹配是面向行的。像grep这样的程序尝试在单个输入行上匹 配一个模式。这就使它很难匹配一个在一行的结尾处开始。并在下一行的开始处结束的短语。其他一些 模式只有当在多行上重复时才有意义。
sed能查看模式空间的多个行,这就是允许匹配模式扩展到多行上,3个多行命令(N、D、P))对应于小 写字母的基本命令(n、d、p)。例如,删除命令(D)是删除命令(d)的多行形式。区别是:d删除模 式空间的内容,D只删除多行模式空间的第一行。
追加下一行
多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空 间。模式空间最初的内容和新的输入行之间用换行符分隔。在模式空间中嵌入的换行符可以利用转义序 列“\n”来匹配。在多行模式空间中,元字符“^”匹配空间中的第一个字条,而不匹配换行符后面的字符。 同样,“$”只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符,在执行next命令之后,控制将被 传递给脚本中的后续命令。
Next命令与next命令不同,next输出模式空间的内容,然后读取新的输入行。next命令不创建多行模式 空间。
例如,我们假设想要将“Owner and Operator Guide”换成“lnstallation Guide”,但是我们发现它出现在 文件中的两行上,“Operator”和“Guide”被分开了。
[root@leigexi ~]# cat test
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system.
[root@leigexi ~]# sed '/Operator$/{N;s/Operator\nGuide/Installation Guide/g}' test
Consult Section 3.1 in the Owner and Installation Guide for a description of the tape drives
available on your system.
$!N
它排除了对最后一行($)执行Next命令。在以上的脚本中,通过匹配最后一行
上的“Owner and Operator Guide” ,我们避免了匹配“Owner” 和 应用N命令。然而,如果“Owner” 出现在最后一行,我们会遇到同样的问题,除非使用“$!N”
案例:
[root@leigexi ~]# cat text
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system
[root@leigexi ~]# sed -n '/Section/{$!N;p}' text
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
[root@leigexi ~]# sed '/Section/{$!N;s/Operator\nGuide/Installation Guide/g}' text
Consult Section 3.1 in the Owner and Installation Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Installation Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Installation Guide for a description of the tape drives
available on your system
转换 Interleaf 文件
我们的转换证明了更改命令对多行模式空间的影响。在
Interleaf文件中,“<para>” 标记一个段落。标签的前后是空行,请看样本文件
[root@leigexi ~]# cat qwe
<para>
This is a test paragraph in Interleaf style ASCII. Another line
in a paragraph. Yet another.
<Figure Begin>
v.11111110000001111110000
1000001001000100000
000
<Figure End>
<para>
More lines of text to be found after the figure.
These lines should print.
为了将这个文件转换成troff宏,我们必须用宏(.LP)取代 ”<para>“ 代码,然而,还
要做一些处理,因为需要删除跟在代码后面的空行。有几种方式可以完成该功能,但
是我们将使用Next命令创建多行模式空间,它由 ”<para>“ 和空行组成,然后使用更改
命令用段落宏取代模式空间的内容。
/<para>/{
N
c\
.LP
}
这个地址匹配具有段落标签的行,Next命令将下一行(应该是空行)追加到模式空行中。这里使用Next命令(N)而不是next命令(n),是因为我们不想输出模式空间的内容。更改命令改写模式空间以前的内容(后面有换行符的”<para>“ )即使在模式空间包含多行的时候。
案列:
[root@leigexi ~]# cat qwe
<para>
This is a test paragraph in Interleaf style ASCII. Another line
in a paragraph. Yet another.
<Figure Begin>
v.11111110000001111110000
1000001001000100000
000
<Figure End>
<para>
More lines of text to be found after the figure.
These lines should print.
[root@leigexi ~]# sed '
/<para>/{
N
c\
.LP
}' qwe
.LP
in a paragraph. Yet another.
<Figure Begin>
v.11111110000001111110000
1000001001000100000
000
<Figure End>
.LP
These lines should print.
在这个脚本中,我们将提取位图图形数据,并把它写到一个独立文件中。
在它的位置上,我们插入标记文件中图形的图形的图形宏
/<Figure Begin>/,/<Figure End>/{
w fig.interleaf
/<Figure End>/i\
.FG\
<insert figure here>\
.FE
d
}
z这个过程匹配”<Figure Begin>” 和 “<Figure End>” 之前的行,并且把它们
写到文件fig. intetleaf中。每次指令被匹配时,删除命令都将被执行。删除已
经被写到文件中的行。当“<Figure End>” 被匹配时,将一对宏插入到输出中
图形所在的位置。注意,后续的删除命令不会影响插入命令的文件输出,然
而,他从模式空间中删除“<Figure End>” 。
案例:
[root@leigexi ~]# cat qwe
<para>
This is a test paragraph in Interleaf style ASCII. Another line
in a paragraph. Yet another.
<Figure Begin>
v.11111110000001111110000
1000001001000100000
000
<Figure End>
<para>
More lines of text to be found after the figure.
These lines should print.
[root@leigexi ~]# sed '
/<Figure Begin>/,/<Figure End>/{
w fig.interleaf
/<Figure End>/i\
.FG\
<insert figure here>\
.FE
d
}' qwe
<para>
This is a test paragraph in Interleaf style ASCII. Another line
in a paragraph. Yet another.
.FG
<insert figure here>
.FE
<para>
More lines of text to be found after the figure.
These lines should print.
[root@leigexi ~]# ls |grep fig
fig.interleaf
[root@leigexi ~]# cat text
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives Operator
Guide Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system
[root@leigexi ~]# sed '
/^Guide/,/^available/{
w 456
/available/i\
Guide for a description of the tape drives\navailable on your system
d
}' text
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system
多行删除
删除命令(d)删除模式空间的内容并导致读入新的输入行,从而在脚本的顶端
重新使用编辑方法。与删除命令(D)稍微有些不同:它删除模式空间中直到第一个嵌入的换行符的这些内容。下面语句使用了删除命令(d):
/^$/{
N
/^\n$/d
}
a案列:
[root@leigexi ~]# cat text This line is followed by 1 blank line. This line is followed by 2 blank line. This line is followed by 3 blank line. This line is followed by 4 blank line. This is the end. [root@leigexi ~]# sed ' /^$/{ N /^\n$/d }' text This line is followed by 1 blank line. This line is followed by 2 blank line. This line is followed by 3 blank line. This line is followed by 4 blank line. This is the end. //也可以横向命令 [root@leigexi ~]# sed '/^$/{N;/^\n$/d}' text This line is followed by 1 blank line. This line is followed by 2 blank line. This line is followed by 3 blank line. This line is followed by 4 blank line. This is the end.
多行打印
多行打印(Print)命令与小写字母的Print命令稍有不同。该命令输出多行模式
空间的第一部分,直到第一个嵌入的换行符为止。在执行完脚本的最后一个命令
之后,模式空间的内容自动输出(-n 选项或#n 抑制这个默认的动作)。因此
当默认的输出被抑制或者脚本中的控制流更改,以至于不能到达脚本的底部时,
需要使用打印命令(P或p),Print命令经常出现在Next命令之后和Delete命令
之前。这3个命令能建立一个输入/输出循环,用来维护两行的模式空间,但是一次
只能输出一行。
Next命令将一个新的输入行追加到模式空间的当前行。在替换命令应用于多行模式空间之后,模式空间的第一部分被Print命令输出,然后被Delete命令删除。这意味着当前被输出并且新的行成为当前行。Delete命令阻止脚本到达底部,这将输出两行并清除模式空间的内容。Delete命令让我们保护了模式空间的第二部分,并将控制转移动脚本的顶端,在顶端所有的编辑命令都可以被应用于一行。这些命令中有一个是Next命令,它将另一个新行读入模式空间。
案例:
[root@leigexi ~]# cat text
Here are examples of the UNIX
System. Where UNIX
System appears, it should be the UNIX
Operating System.
[root@leigexi ~]# sed '
/UNIX$/{
N
/\nSystem/{
s// Operating &/
p
D
}}' text
Here are examples of the UNIX Operating
System. Where UNIX
System. Where UNIX Operating
System appears, it should be the UNIX
System appears, it should be the UNIX
Operating System.
[root@leigexi ~]# cat text
hello world runtime
yqh, where runtime
yqh, what runtime
it yqh.
[root@leigexi ~]# sed '
/runtime$/{
N
/\nyqh/{
s// it &/
P
D
}}' text
hello world runtime it
yqh, where runtime it
yqh, what runtime
it yqh.
包含那一行
模式空间是容纳当前输入行的缓冲区。还有-一个称为保持空间(hold space)的顶留(set-aside)缓冲区。模式空间的内容可以复制到保持空间,而且保持空间的内容也可以复制到模式空间。有一组命令用于在保持空间和模式空间之间移动数据。保持空间用于临时存储。单独的命令不能寻址保持空间或者更改它的内容。
保持空间最常的用途是,当改变模式空间中的原始内容时,用于保留当前输入行的副本。影响模式空间的命令有:
命令 | 缩写 | 功能 |
Hold | h 或 H | 将模式空间的内容复制或追加到保持空间 |
Get | g 或 G | 将保持空间的内容复制或追加到模式空间 |
Exchange | x | 交换保持空间和模式空间的内容 |
这些命令中的每一条都可以利用一个地址来指定一行或行范围。Hole(h,H)命令将数据移至保持空间、而get (g.G)命令将保持空间的数据移回到模式空间。同一命令的小写字母和大写字母之间的差别是,小字字母命令改写目的缓存区的内容,而大写字母命令追加缓存区的现有内容。
Hole命令在保持空间的内容之后放置一个换行符,且后面跟随模式空间的内容(即使保持空间是空的,换行符也被追加到保持空间中)。Get命令模式空间的内容之后放置一个换行符,且后面跟随保持空间的内容。
交换命令交换两个缓存区的内容,对两个缓存区没有副作用。
这里的目的是颠倒以1开始的行和以2开始的行的顺序,将第一行复制到保持空间(它一直在那),这时清除模式空间,然后sed将第二行读入模式空间,并且将保持空间的行追加到模式空间的结尾。请看下面的脚本
# 反转 flip /1/{ h d } /2/{ G }
案例:
[root@leigexi ~]# cat text
1
2
11
22
111
222
[root@leigexi ~]# sed '
> /1/{
> h
> d
> }
> /2/{
> G
> }' text
2
1
22
11
222
111
[root@leigexi ~]# sed '
> /1/{
> h
> d
> }
> /2/{
> g
> }' text
1
11
111
匹配“1”的任何行都被复制到保持空间并且从模式空间删除,控制转移到脚本的顶端并且不打印那一行,当读取下一行时,它匹配模式“2”且将已经复制到保持空间的行追加到模式空间之后,然后两行都被打印出来,保存这两行中的第一行并且直到匹配第二行时才输出它。
构建文本块
保持空间可用于在输出行块之前收集它们,一些troff请求和宏是面向块的,这命令中必须包围文件块。通常在块开始处的代码用启用格式,而大块结尾处的代码用禁用格式。HTML编码的文档还包含许多面向块的结构。例如,“《p》”和“《/p》”分别用于开始和结束一个段落。输入文件包含由可变长度的行组成的段落,段落之间都有一个空行。因此,脚本必须将空行之前的所有行收集到保持空间。检索保持空间的内容并且用段落标签包围这些内容。
下面是脚本:
/^$/!{ H d } /^$/{ x s/^\n/<p>/ s/$/<\/p>/ G }
案列:
[root@leigexi ~]# cat 10
I am Chinese
hello world
abc
asd
123
456
end
[root@leigexi ~]# sed '
> /^$/!{
> H
> d
> }
> /^$/{
> x
> s/^\n/<p>/
> s/$/<\/p>/
> G
> }' 10
<p>I am Chinese
hello world</p>
</p>
<p>abc
asd</p>
<p>123
456</p>
</p>
<p>end</p>