Sed案例1

Sed案例1


替换

替换命令有许多用法,下面是它的详细的用法:

[address]s/pattern/replacement/flags

这里修饰替换的标志flags是:

选项 描述
n 1到512之间的一个数字,表示对文本模式中指定模式第n次出现的情况进行替换
g 对模式空间的所有出现的情况进行全局更改,而没有g是通常只有第一次出现的情况被取代
p 打印模式空间的内容
w 将模式空间的内容写到文件file 中

替换命令应用于与address 匹配的行。如果没有指定地址,那么就应用于Pattern匹配的所有行。如果正则表达式作为地址来提供,并且没有指定模式,那么替换命令匹配由地址匹配的内容。当替换命令是应用于同一个地址上的多个命令之一时,这可能会非常有用。可以参看本章后面的“检验参考页”一节中的示例。

和地址不同的是,地址需要一个作为定界符的斜杠(/) ,而正则表达式可以用任意字符来分隔,只有换行符除外。因此,如果模式包含斜杠,那么可以选择另一个字符作为定界符,例如井号。

s#/usr/mail#/usr2/mail#

注意,定界符出现了3次而且在replacement之后是必需的。不管使用哪种定界符,如果它出现在正则表达式中,或者在替换文本中,那么就用反斜杠来转义它。

从前,计算机用固定长度的记录来存储文本。一行在出现许多字符(一般为80个)之后结束,然后开始下一行。数据中没有显式的字符来标记一行的结束和下一行的开始,每一行都有相同的(固定的)数量字符。现在的系统比较灵活,它们使用特殊的字符(称为换行符(newline))标记行的结束,这样就允许行行的长度为任意。

因为在内部存储时换行符只是一个字符,所以正则表达式可以使用“ ”来匹配嵌入的换行符。

Replacement是一个字符串,用来替换与正则表达式匹配的内容,在replacement部分,只用下列字符有特殊含义:

选项 描述
& 用正则表达式匹配的内容进行替换
匹配第n个字串(n是一个数字),这个字串以前在pattern 中用“、(”和“、)”指定
当在替换部分包含“与“符号(&),反斜杠()和替换命令的定界符时可用转义它们,另外,它用于转义换行符并创建多行replacement字符串。

&的用法

//文本file1的内容如下
[root@yqh ~]# cat file1
Alice Ford, 22 East Broadway, Richmond VA

//将22替换成223
[root@yqh ~]# sed 's/22/&3/' file1
Alice Ford, 223 East Broadway, Richmond VA

//将22替换成22 3
[root@yqh ~]# sed 's/22/& 3/' file1
Alice Ford, 22 3 East Broadway, Richmond VA

//将22替换成322
[root@yqh ~]# sed 's/22/3&/' file1
Alice Ford, 322 East Broadway, Richmond VA

//匹配2位的整数在其后面加上3
[root@yqh ~]# sed -r 's/[0-9]{2}/&3/' file1
Alice Ford, 223 East Broadway, Richmond VA

替换元字符

替换元字符是反斜杠()、“与”符号(&)和 ,反斜杠一般用于转义其他的元字符,但是他在替换字符串中也用于包含换行符。

来自于将troff文件转换成Ventura Publisher的 ASCIl输入格式,它将下面的troff行:

.Ah "Major Heading"

转换成类似的Ventura Publisher行:

@A HEAD = Major Heading

这个问题中的难点是这一行需要前后都有空行,这是一个编写多行替换字符串的问题。

//文本file2内容如下
[root@yqh ~]# cat file2 
.Ah "Major Heading"

[root@yqh ~]# sed '
> /^.Ah */{
> s/.Ah */
> 
> @A HEAD = /
> s/"//g
> s/$/
> /
> }' file2


@A HEAD = Major Heading

第一个替换命令用两个换行符和“@A HEAD =”取代“.Ah”,在行结尾处有必要用反斜杠转义换行符。第二个替换删除了引号。最后一个命令匹配模式空间中的行的结尾(不是嵌入的换行符),并在它后面添加一个换行符。

作为元字符,“与”符号(&)表示模式匹配的范围,不是被匹配的行。可以使用“与”符号匹配一个单词并且用troff 请求来包围它。下面的示例用点数请求包围一个单词:

s/UNIX/\s-2&\s0/g

因为反斜杠也是替换字符串中的元字符,所以需要用两个反斜杠来输出一个反斜杠,替换字符串中的“&”表示“UNIX”。

//文本file3内容如下
[root@yqh ~]# cat file3
on the UNIX Operating System.

[root@yqh ~]# sed 's/UNIX/\s-2&\s0/g' file3
on the s-2UNIXs0 Operating System.

当正则表达式匹配单词的变化时,“与”符号特别有用。它允许指定一个可变的替换字符串,该字符串相当于匹配的内容与实际内容匹配的字符创。例如,假设要用圆括号括住文档中对已编号部分的任意交叉引用。换句话说,任意诸如“See Section 1.4”或“See Section 12.9”的引用都应该出现在圆括号中,如“(See Section 12.9)”。正则表达式可以匹配数字的不同组合,所以在替换字符串中可以使用“&”并括起所匹配的内容。

//文本file4内容如下
[root@yqh ~]# cat file4
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

//给See Section (任意小数)两边加上括号
[root@yqh ~]# sed 's/See Section [1-9][0-9]*.[1-9][0-9]*/(&)/' file4
(See Section 1.4)
(See Section 12.34) 
(See Section 12.9)
(See Section 789.11)
(See Section 55.666)
(See Section 3.26)

“与”符号用于在替换字符创中引用整个匹配内容。

现在,我们来看一种元字符,它用于选择被匹配的字符串的任意独立部分,并且在替换字符创中回调它。在sed中转义的圆括号括住正则表达式的任意部分并且保存它以备回调。一行最多允许“保存”9次。“ ”用于回调被保存的匹配部分,n是从1到9的数字,用于饮用特殊“保存的”备用字符串。

例如,当节号出现在交叉引用中时要表示为用粗体,可以编写下面的替换:

//文本file4内容如下
[root@yqh ~]# cat file4
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

//将小数加粗
[root@yqh ~]# sed -r 's/(See Section) ([1-9][0-9]*.[1-9][0-9]*)/1 \fB2\fP/' file4
See Section fB1.4fP
See Section fB12.34fP 
See Section fB12.9fP
See Section fB789.11fP
See Section fB55.666fP
See Section fB3.26fP

删除

删除命令(d)采用一个地址,如果行匹配这个地址就删除模式空间的内容。

删除命令还是一个可以改变脚本中的控制流的命令,这是因为一旦执行这个命令,那么在“空的”模式空间中就不会再有命令执行,删除命令会导致读取新输入行,而编辑脚本则从头开始新的一轮。

重要的是:如果某行匹配这个地址,那么就删除整个行,而不只是删除行中匹配的部分(要删除行的一部分,可以使用替换命令并指定一个空的替换)。

//文本file4内容如下
[root@yqh ~]# cat file4
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

//删除整数部分为1位的小数的所在行的数据
[root@yqh ~]# sed -r '/See Section [1-9].[1-9][0-9]*/d' file4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666

追加、插入和更改

追加(a)、插入(i)和更改(c)命令提供了通常在交互式编辑器(例如vi)中所选的编辑功能。你会奇怪地发现、可以使用这些相同的命令在非交互编辑器中“输入”文本。这些命令的语法在sed中不常用,因为它们必须在多行上来指定。语法如下:

追加[line-address]a
		text
插入[line-address]i
		text
更改[address]c
		text

插入命令将所提供的文本放置在模式空间的当前行之前。追加命令将文本放置在当前行之后。更改命令用所提供的文本取代模式空间的内容。

//文本file4内容如下
[root@yqh ~]# cat file4
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

//匹配12.9所在行,在其上面加上123
456
[root@yqh ~]# sed '/12.9/i123
456' file4
See Section 1.4
See Section 12.34 
123
456
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

追加命令和插入命令只应用于单个行地址,而不是一个范围内的行。然而,更改命令可以处理一个范围内的行。在这种情况下,它用一个文本备份取代所有被寻址的行。换句话说,它删除这个范围中的所有行,但是提供的文本只被输出一次。例如,当下面的脚本在包含邮件消息的文件上运行时:

//文本test内容如下
[root@yqh ~]# cat test
Here are the books that you requested
Yes, it is a good book for children

It is amzing to think that it was called a "harmful book" when
once you get to the end of the book, you can't believe

//匹配H开头空行结尾,将其更改为123
[root@yqh ~]# sed '/^H/,/^$/c123' test
123
It is amzing to think that it was called a "harmful book" when
once you get to the end of the book, you can't believe

转换

转换命令是特有的,不仅因为它在所有的sed命令中拥有最小的肋记符,这个命令按位置将字符串abc 中的每个字符,都转换成字符串xyz中的等价字符。它的语法如下:

[address]y/abc/xyz/

替换根据字符的位置来进行。因此,它没有“词”的概念。这样,在该行上的任何地方的“a”都被换成了“x”,而不管它后面是否跟有“b”。这个命令的一个可能的用处是用大写字母替换对应的小写字母,

y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/

这个命令影响整个模式空间的所有内容。如果想在输入行上转换单个单词,那么通过使用保持空间可以完成。(大致过程是:输出更改单的那一行之前的所有行,删除这些行,将单词后面的行复制到保持空间,转换这个单词,然后将保持空间的内容追加到模式空间)。

//文本test内容如下
[root@yqh ~]# cat test
Here are the books that you requested
Yes, it is a good book for children

It is amzing to think that it was called a "harmful book" when
once you get to the end of the book, you can't believe

//将文本中a转换为1,b转换为2,c转换为3,d转换为4,e转换为5,f转换为6
[root@yqh ~]# sed 'y/abcdef/123456/' test
H5r5 1r5 th5 2ooks th1t you r5qu5st54
Y5s, it is 1 goo4 2ook 6or 3hil4r5n

It is 1mzing to think th1t it w1s 31ll54 1 "h1rm6ul 2ook" wh5n
on35 you g5t to th5 5n4 o6 th5 2ook, you 31n't 25li5v5

打印

打印命令(p)输出模式空间的内容。它既不清除模式空间也不改变脚本中的控制流。然而,它频繁地用在改变流控制的命令(d,N,b)之前。除非抑制(-n)默认的输出,否则打印命令将输出行的重复复制。当抑制默认的输出或者当通过程序的流控制来避免到达脚本的底部时,可能会使用它。

打印行号

跟在地址后面的等号(=)打印被匹配的行的行号。除非抑制行的自动输出,行号和行本身将被打印。它的语法如下:

[line-address]=

这个命令不能对一个范围内的行进行操作。

//文本file4内容如下
[root@yqh ~]# cat file4
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

//在每行前打印行号
[root@yqh ~]# sed -n '/[1-9][0-9]*.[1-9][0-9]*/{=;p}' file4
1
See Section 1.4
2
See Section 12.34 
3
See Section 12.9
4
See Section 789.11
5
See Section 55.666
6
See Section 3.26

下一步

下一步(next)命令(n)输出模式空间的内容,然后读取输入的下一行,而不用返回到脚本的顶端。它的语法如下:

[address]n

next命令改变了正常的流控制,直到到达脚本的底部才会输出模式空间的内容,它总是在读入新行之后从脚本的顶端开始。实际上,next命令导致输入的下一行取代横穿空间中的当前行,脚本中的后续命令应用于替换后的行,而不是当前行。如果没有抑制默认输出,那么在替换发生之前会打印当前行。

下面我们来看next命令的示例,在这个例子中,当空行跟随一个匹配模式的行时,则删除该空行。在这种情况中,假设作者已经在节标题宏(Yes)之后插入一个空行。我们想要删除这个窄而不是删除文件中所有的空行。下面是示例:

//文本test内容如下
[root@yqh ~]# cat test
Here are the books that you requested
Yes, it is a good book for children

It is amzing to think that it was called a "harmful book" when
once you get to the end of the book, you can't believe

//删除空行
[root@yqh ~]# sed '/Yes/{n;d}' test
Here are the books that you requested
Yes, it is a good book for children
It is amzing to think that it was called a "harmful book" when
once you get to the end of the book, you can't believe

可以按下面的方式阅读这个脚本:匹配字符串"Yes"的行,然后打印那一行并读入下一行。如果那一行为空,则删除它。大括号用于在同一个地址应用多个命令。

在较长的脚本中,必须记住出现在next命令之前的命令不会应用于新的输入行,而且出现在后面的命令不应用于旧的输入行。


读和写文件

读(r)和写(w)命令用于直接处理文件,这两个命令都只有一个参数,即文件名。语法如下:

[line-address]r file
[address]w file

读命令将由file指定的文件确定的行之后的内容读入模式空间。它不能对一个范围内的行进行操作。写命令将模式空间的内容写到file 中。

在命令和文件名之前必须有一个空格(空格后到换行符前的每个字符都被当做文件名.因此,前导的和嵌入的空格也是文件名的一部分)。如果文件不存在,读命令也不会报错。如果写命令中指定的文件不存在,将创建一个文件;如果文件已经存在,那么写命令将在每次调用脚本时改写它。如果一个脚本中有多个指令写到同一个文件中,那么每个写命令都将内容追加到这个文件中。而且,每个脚本最多只能打开10个文件。

读命令对于将一个文件的内容插入到另一个文件的特定位置是很有用的。例如,假设有一组文件并且每个文件都应以相同的一个或两个段落的语句结束,使用sed脚本可以在必要时分别单独对结束部分进行维护。

//将file4文件的内容写入到test文件内容的匹配Yes行的下面
[root@yqh ~]# sed '/Yes/r file4' test
Here are the books that you requested
Yes, it is a good book for children
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

It is amzing to think that it was called a "harmful book" when
once you get to the end of the book, you can't believe

退出

退出命令(q)会使sed停止读取新的输入行(并停止将它们发送到输出)。它的语法为:

[line-address]q

它只适用于单行的地址,一旦找到和address 匹配的行,那么脚本就结束。

//文本file4内容如下
[root@yqh ~]# cat file4
See Section 1.4
See Section 12.34 
See Section 12.9
See Section 789.11
See Section 55.666
See Section 3.26

//一直匹配直到找到12.9所在行
[root@yqh ~]# sed '/12.9/q' file4
See Section 1.4
See Section 12.34 
See Section 12.9

//匹配3行
[root@yqh ~]# sed '3q' file4
See Section 1.4
See Section 12.34 
See Section 12.9

高级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)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间。模式空间最初的内容和新的输入行之间用换行符分隔。在模式空间中嵌入的换行符可以利用转义序列“ ”来匹配。在多行模式空间中,元字符“^”匹配空间中的第一个字条,而不匹配换行符后面的字符。同样,“$”只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符,在执行next命令之后,控制将被传递给脚本中的后续命令。

Next命令与next命令不同,next输出模式空间的内容,然后读取新的输入行。next命令不创建多行模式空间。

例如,我们假设想要将“Owner and Operator Guide”换成“lnstallation Guide”,但是我们发现它出现在文件中的两行上,“Operator”和“Guide”被分开了。

//文本text内容如下
[root@yqh ~]# cat text
Consult Section 3.1 in the Owner and Operator
Guide for a description of the tape drives
available on your system.

//匹配以Operator结尾以及下行的Guide,合并成一行替换成Installation Guide
[root@yqh ~]# sed '/Operator$/{N;s/Operator
Guide/Installation Guide/g}' text
Consult Section 3.1 in the Owner and Installation Guide for a description of the tape drives
available on your system.
原文地址:https://www.cnblogs.com/yuqinghao/p/14592826.html