`
icepp
  • 浏览: 10396 次
  • 性别: Icon_minigender_1
  • 来自: 大连
最近访客 更多访客>>
社区版块
存档分类
最新评论

Sed基础二

阅读更多

 

Sed的高级命令,按照《o’reilly sed and awk》分法,分成如下三组:(本文很多例子也出自这本书)

一  处理多行模式空间(N  D  P)
二  采用保持空间来保存模式空间的内容并使它可用于后续的命令(H h G g x)
三  使用分支和条件指令更改脚本的控制流(: b  t)

Sed脚本中, 正常的控制流是:一行被读入模式空间并且用脚本的每个命令逐个地应用于那一行,当到达脚本的底部时,输出这一行并且清空模式空间,然后新行被读入模式空间,控制被转移到脚本的顶端。

在这里, 我们将改变脚本控制流,按照我们的预期来执行。

 

第一部分  N D P命令

 

N命令:
多行N命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间。最初内容与新行直接用\n分隔,sed将它看作一个有很多嵌入行的整行。

小n命令区别在于它输出模式空间内容,然后读取新行, 并不建立多行模式空间。

示例:

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",但它出现在文件的两行上,

/Operator$/{
N
s/Owner and Operator\nGuide/Installation Guide/
}

避免产生超长行 ,可以s/Owner and Operator\nGuide/Installation Guide\n/

实际上, Owner and Operator Guide可能在不同的位置上分成多行,我们可以修改正则,下面是一个完整的脚本:

s/Owner and Operator Guide/Installation Guide/
/Owner/{
$!N
s/ *\n/ /
s/Owner and Operator Guide */Installation Guide\
/
}

 

D命令:
删除命令D是删除命令d的多行形式,区别在于d删除模式空间的内容并读入新行,从而在脚本顶端重新使用编辑方法。
D只删除多行模式空间的第一个嵌入的换行符以前的内容,它不会导致读入新行,相反,它返回到脚本的顶端,将这些指令应用与模式空间剩余的内容。

示例:

# 将多个空行减少到一个空行,使用d命令版本
/^$/{
 N
 /^\n$/d
}

测试文件如下:
This line is followed by 1 blank line.

This line is followed by 2 blank lines.


This line is followed by 3 blank lines.

 

This line is followed by 4 blank lines.

 


This is the end.


运行脚本产生一行结果:
[icepp@fc8 test]$ sed -f sed.blank test.blank
This line is followed by 1 blank line.

This line is followed by 2 blank lines.
This line is followed by 3 blank lines.

This line is followed by 4 blank lines.
This is the end.

当有偶数个空行时,所有空行都被删掉。仅当有奇数行时,有一行被保留下来,这是因为d命令删除整个模式空间的内容,一旦遇到第一个空行,就读入下一行,并且两行都被删除。如果遇到第三行,并且下行不为空行,那么d命令就不会执行,因此空行被输出。

我们将d命令换成D命令,测试如下:
[icepp@fc8 test]$ sed -f sed.blank test.blank
This line is followed by 1 blank line.

This line is followed by 2 blank lines.

This line is followed by 3 blank lines.

This line is followed by 4 blank lines.

This is the end.

得到我们预期的结果。多行Delete的工作完成的原因:当遇到两个空行的时候,D命令只删除两个空行的第一个,下次遍历脚本的时候, 将导致另一行被读入模式空间。如果那行不为空,那么两行都输出,因此确保了输出一个空行。也就是当模式空间有两个空行的时候,只有第一个空行被删除。当一个空行跟有文本的时候,模式空间的内容都输出。


P命令:
多行Print和小print稍有不同。它输出多行模式空间的第一部分,直到第一个嵌入的换行符。执行完脚本的最后一个命令后,模式空间的内容自动输出(-n选项将抑制这个默认的动作)。
因此,当默认输出被抑制或脚本的控制流更改,以至于不能到达脚本底部的时候,需要使用打印命令P或者p。Print命令经常出现在Next和Delete命令之前。这三个命令能够建立一个输入输出循环,用来维护两行的模式空间,但是一次只输出一行,然后返回到脚本的顶端将所有命令应用于模式空间的第二行。没这个循环,当执行到脚本的最后一个命令的时候,模式空间这两行将被输出。

示例:
测试文件
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
        }
}

执行结果如下
[icepp@fc8 test]$ sed -f sed.Print test.Print
Here are examples of the UNIX Operating
System.  Where UNIX Operating
System appears, it should be the UNIX
Operating System.


创建多行模式空间以匹配第一行结尾的“UNIX”和第二行的开始的“System”,如果发现“UNIX System”跨越两行,我们就将它变成“UNIX Operating System”。建立这个循环以返回到脚本顶端,并寻找第二行结尾的“UNIX”。
首先, Next将一个新行追加到模式空间的当前行。在替换命令应用与多行模式空间后,模式空间的第一部分被Print输出,然后被D命令删除。这样,当前行被输出并且新行成为当前行。D命令阻止到达脚本底部输出并清空模式空间的两行,并将控制转移到了脚本顶部,N命令重新将一个新行读入模式空间,这样就形成了循环。


第二部分 H h G g x命令


模式空间(pattern space)是容纳当前输入行的缓冲区。Sed还使用一个称为保持空间(hold space)的预留(set-aside)缓冲区。
这部分的命令就是用于在模式空间和保留空间之间移动数据,保持空间用于临时存储,单独的命令不能寻址保持空间或者更改它的内容。

hold命令(H, h)将数据转移至保持空间。
get命令(G, g)将保持空间的数据移至模式空间。
小写字母命令改写目的缓存区的内容,而大写字母命令是追加缓存区的现有内容。

Exchange命令(x)交换保持空间和模式空间的内容。


示例1:反转行的顺序,颠倒1和2开始的行

样本文件
1
2
11
22
111
222

脚本文件
# Reverse flip
/1/{
h
d
}
/2/{
G
}

执行结果
[icepp@fc8 test]$ sed -f sed.flip test.flip
2
1
22
11
222
111

首先, 我们将第一行h复制到保持空间,然后d清除模式空间,sed将读入下一行,G命令将保持空间的内容追加append到模式空间。匹配“1”的行都被复制到保持空间并从模式空间删除,控制转移到脚本的顶端并且不打印那一行。我们保存这两行中的第一行并且直到匹配第二行时才输出它。

Hold 命令后面跟delete命令是一种常见的搭配。没有delete命令,控制将一直进行到脚本的底部,并且模式空间的内容将被输出。如果脚本中使用next(n)命令而不是delete命令,那么模式空间的内容也会被输出。
这仅仅是一个用于演示的逻辑很差的脚本。


示例2:
样本文件
find the Match statement
Consult the Get statement.
using the Read statement to retrieve data

我们将要完成
s/find the Match statement/find the MATCH statement/g

使用脚本
# 将语句的名字变成大写形式
/the .* statement/{
h
s/.*the \(.*\) statement.*/\1/
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
G
s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/
}

地址将过程限制在匹配the .* statement的行上

h      hold命令将当前输入行复制到保持空间。使用样本行”find the Match statement”,我们来显示模式空间和保持空间的内容。应用h命令后:
pattern space:  find the Match statement
hold space:    find the Match statement

s/.*the \(.*\) statement.*/\1/
   这个替换命令从行中取出语句的名字,并且用它来替代整个行
 Pattern space: Match
 Hold space  :

y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
  这个转换命令将每个小写字母换成大写字母。
 pattern space:  MATCH
 hold space  :  find the Match statement

G Get命令将保持在保持空间的内容追加到模式空间
 pattern space: MATCH\nfind the Match statement
 hold space: find the Match statement

s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/
  这个替换命令匹配模式空间的3个部分: 1)嵌入的换行符之前的所有字符 2)从嵌入的换行符开始直到后面跟有一个空格的the,且包括the在内的所有字符 3)以空格并且后面跟有statement开始直到模式空间结尾的所有字符。
 pattern space: find the MATCH statement
 hold space  : find the Match statement


运行脚本后的结果:
find the MATCH statement
Consult the GET statement.
using the READ statement to retrieve data

 


第三部分  分支和条件指令更改脚本的控制流(: b  t)

分支branch和测试命令将脚本中的控制转移到包含特殊标签的行。如果没有指定标签,则控制转移到脚本结尾。分支branch命令用于无条件转移,测试test命令用于有条件转移。
标签是任意不多于7个字符的序列,本身以冒号开始并占据一行。
:mylabel


用法简单示例:

command1
/pattern/b end
command2
:end
command3


command1
/pattern/b dothree
command2
b
:dothree
command3

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics