第六章 高级sed命令
1. 高级命令主要分成3组:
(1) 处理多行模式空间(N, D, P)
(2) 采用保持空间来保存模式空间中的内容并使它可用于后续的命令(H, h, G, g, x)
(3) 编写使用分支和条件指令的脚本来更改控制流(:, b, t)
1. 多行模式空间:
(1) 追加下一行(N): 多行命令通过读取新的输入行,并将其添加到模式空间的现有内容之后来创建多行模式空间,模式空间最初的内容和新的输入行之间用换行符分割,在模式空间中嵌入的换行符可以通过转义字符\n来匹配,在多行模式空间中,元字符^匹配模式空间中的第一个字符,而不匹配换行符后面的字符,同样,$只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符,在执行Next(N)命令后,控制将被传递给脚本中的后续命令,与next(n)命令不同的是,next输出模式空间的内容,然后读取新的一行。
(2) 多行删除(D): 删除命令d删除模式空间中的内容并自动读取新的输入行,从而在脚本的顶端重新使用编辑方法,D删除命令稍微有些不同,它删除的是模式空间中直到第一个嵌入的换行符的这部分内容(可以看到,基本上D删除命令只是删除多行中的第一行),另外,它不会导致读入新的输入行,并且它返回的是脚本的顶端!
【举例】
测试文件:
删除命令组:
测试结果:
【解释】首先,一定要理解“模式空间是以^符号开始,并以$符号结束的”这句话,“^\n$”实际上匹配的是两个空行。因此,原命令组的含义是先定位每个空行,然后追加每个空行的下一行,若这两个时空行,则删除之,否则,跳过。若将删除命令换成D,则结果将不同,这是因为当遇到两个空行时,则会首先删除第一个空行,并在下次遍历脚本时,将下一行进行读入,若这行是空白的,则将会继续删除,否则一起输出。这正是当有多行空格时,依然最后只保留一个空格的原因。
(3)多行打印命令(P):多行打印命令与p命令的差别在于,该命令只是输出多行模式空间的第一部分,直到第一个嵌入的换行符为止,在执行完脚本的最后一个命令后,模式空间的内容会自动输出(可以使用-n选项进行抑制),
♥ P命令经常出现在N之后和D之前,这三个命令可以形成一个输入/输出循环,用来维护两行的模式空间,但是一次只能输出一行,然后返回到脚本的顶端将所有的命令应用于模式空间的第二行。
♥ 对P输出的理解可参考前面的多行删除命令D.
♥ 实例分析:
测试文件:(test)
Here are examples of the UNIX System. Where UNIX System appears, it should be the UNIX Operating System. |
/UNIX$/{ N /\nSystem/{ s// Operating &/ P D } } |
/UNIX$/{ N s/\nSystem/ Operating &/ P D } |
Here are examples of the UNIX Operating System. Where UNIX Operating System appears, it should be the UNIX Operating System. |
【分析】上面的sed脚本有两个,二者是等价的,作用均是将所匹配的\nSystem替换为
Operating \nSystem, 注意前面所讲的sed中替换的replacement中的几个特殊符号所代表的含义,&则是代表前面所代表的匹配字符,即“\nSystem”;另外替换中若没指定地址,则将所匹配的pattern进行替换,在这个地方, s// Operating &/ 表示将所匹配的\nSystem进行替换。
3 包含哪一行:(H,h,G,g)
♥ 保持空间:保持空间是一个预留缓冲区,它可以与模式空间中的内容进行交换,它最常见的用途是,在
改变模式空间中的内容时,用于保留当前输入行的副本。影响模式空间的命令有:
【注意】大小写命令之间的区别是:小写命令直接改写目的缓存区的内容,而大写命令则是追加缓存
区的现有内容。Hold命令会在保持空间的内容之后放置一个换行符,然后后面跟随模式空间的内容,
尽管保持空间中的内容可能会是空的;Get命令在模式空间的内容之后放置一个换行符,然后后面跟
随保持空间的内容。交换命令则用来交换两个缓存区的内容,这对两个缓存区是没有任何副作用的。
♥ 实例分析:
测试文件:
find the Match statement Consult the Get statement. using the Read statement to retrieve data |
sed脚本:
/the .* statement/{ h s/.*the \(.*\) statement.*/\1/ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ G s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/ } |
结果与分析:sed –f sed test
【分析】这个脚本的主要功能是将the与statement之间的单词全部转换成大写字母,如果单纯用前面的转换命令(y),是不能实现这个功能的,因为转换命令所施作用对象是所有行,必须借助保持空间与模式空间中的缓存交换来实现。
h
pattern space: find the Match statement
hold space: find the Match statement
s/.*the \(.*\) statement.*/\1/
pattern space: Match
hold space: find the Match statement
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
pattern space: MATCH
hold space: find the Match statement
G(追加,另外加上换行符)
pattern space: MATCH\nfind the Match statement
hold space: find the Match statement
s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/
pattern space: find the MATCH statement
hold space: find the Match statement
上面是所匹配的第一行经历脚本之后,模式空间和保持空间中剩余的内容,在此需要解释的是:
替换命令中的\n所代表的含义,它是用来匹配第n个字串,这个字串之前在pattern中用\(和\)指定,因此这个命令类似于“抓取”的功能,只是把整行中某一部分抽取出来。另外注意在书写脚本时,不要忘记字符之间隐藏的空格。
4. 高级的流控制命令:分支(b),测试(t)
(1) 分支和测试命令将脚本中的控制转移到指定的标签行。若没有指定标签,则将控制转移到脚本的结尾
处,其中分支命令是无条件转移,测试命令用于有条件转移,它只有当转换命令改变时才会执行。
标签是任意不多于7个字符的序列,标签本身占据一行并以冒号开始。
:mylable --------------------------中间不能有空格
b mylable ---------------------------命令和标签之间有空格,但不能在标签后面再插入空格
(2) 分支命令用于在脚本中将控制权转移到另一行
[address]b[label] ----------label是可选的,若没有,则跳至脚本结尾处,否则,调至标签后面
分支命令可以用来构造选择和循环过程:
(循环)
(选择,命令1和2只能选其一)
(选择,命令2和3选其一)
(3) 若在当前匹配地址的行上进行成功替换,则test命令就转到标签处,若没有,转到结尾处,实际上实现了条件功能。
5. 综合实例:
跨行查找短语(可能中间出现断裂而出现在不同的行):
#! /bin/sh # phrase -- search for words across lines # $1 = search string; remaining args = filenames search=$1 shift for file do sed ' /'"$search"'/b --------------------第一行出现匹配短语,直接退出并打印 N h s/.*\n// -----------------------只保留第二行,并将前两行存放到保持空间 /'"$search"'/b ----------------第二行出现匹配短语,直接退出打印 g s/ *\n/ / -----------------------将前两行组成一个整体,为后面的检测做准备 /'"$search"'/{ g b } ----------------------------------若整体行出现匹配短语,则将两行同时打印出来 g D' $file -------------------------------防止出现跨行匹配,删除第一行,保留第二行,控制转移到顶端 done |
【注意】这个脚本有个缺陷,总会打印出源test文本中最后一行字符串!