Linux高级文本处理工具之sed(4)

模式空间是sed内部维护的一个缓存空间,它存放着读入的一行或者多行内容。但是模式空间的一个限制是无法保存模式空间中被处理的行,因此sed又引入了另外一个缓存空间——模式空间(Hold Space)。

一、保持空间

保持空间用于保存模式空间的内容,模式空间的内容可以复制到保持空间,同样地保持空间的内容可以复制回模式空间。sed提供了几组命令用来完成复制的工作,其它命令无法匹配也不能修改模式空间的内容。

操作保持空间的命令如下所示:

444b9f37e491249d.png

这几组命令提供了保存、取回以及交换三个动作,交换命令比较容易理解,保存命令和取回命令都有大写和小写两种形式,这两种形式的区别是小写的是将会覆盖目的空间的内容,而大写的是将内容追加到目的空间,追加的内容和原有的内容是以\n分隔。

二、基本使用

实例1:h命令使用

[root@localhost ~]# cat text  1 2 11 22 111 222 [root@localhost ~]# sed 'h' text  1 2 11 22 111 222

实例2:G命令使用

[root@localhost ~]# sed 'G' text  1 2 11 22 111 222 [root@localhost ~]#

说明:实例1返回结果正常,因为复制到保持空间的内容并没有取回;实例2每一行的后面都多了一个空行,原因是每行都会从保持空间取回一行,追加(大写的G)到模式空间的内容之后,以\n分隔。

实例3:使用x命令交换空间

[root@localhost ~]# sed 'x' text  1 2 11 22 111

a.当读入第一行的时候,模式空间中的内容是第一行的内容,而保持空间是空的,这个时候交换两个空间,导致模式空间为空,保持空间为第一行的内容,因此输出为空行;

b.当读入下一行之后,模式空间为第2行的内容,保持空间为第一行的内容,交换后输出第1行的内容;依次读入每一行,输出上一行的内容;

c.直到最后一行被读入到模式空间,交换后输出倒数第二行的内容,而最后一行的内容并没有输出,此时命令执行结束。

高级命令执行过程图解:

c338b66f8093f8d5.png

sedsed调试过程:

[root@localhost ~]# sedsed -d 'H;g' num

PATT:a$

HOLD:$

COMM:H

PATT:a$

HOLD:\na$

COMM:g

PATT:\na$

HOLD:\na$

a

PATT:b$

HOLD:\na$

COMM:H

PATT:b$

HOLD:\na\nb$

COMM:g

PATT:\na\nb$

HOLD:\na\nb$

a

b

PATT:c$

HOLD:\na\nb$

COMM:H

PATT:c$

HOLD:\na\nb\nc$

COMM:g

PATT:\na\nb\nc$

HOLD:\na\nb\nc$

a

b

c

三、流程控制命令

为了使使用者在书写sed脚本的时候真正的"自由",sed还允许在脚本中用":"设置记号,然后用"b"和"t"命令进行流程控制。顾名思义,"b"表示"branch","t"表示"test";前者就是分支命令,后者则是测试命令。 首先来看标签的各式是什么。这个标签放置在你希望流程所开始的地方,单独放一行,以冒号开始。冒号与标签之间不允许有空格或者制表符,标签最后如果有空格的话,也会被认为是标签的一部分。 再来说b命令。它的格式是这样的:

[address]b[label]

它的含意是,如果满足address,则sed流程跟随标签跳转:如果标签指明的话,脚本首先假设这个标签在b命令以下的某行,然后转入该行执行相应的命令;如果这个标签不存在的话,控制流程就直接跳到脚本的末尾。否则继续执行后续的命令。 在某些情况下,b命令和!命令有些相似,但是!命令只能对紧挨它的{}中的内容起作用,而b命令则给予使用者足够的自由在sed脚本中选择哪些命令应该被执行,哪些命令不应该被执行。下面提供几种b命令的

经典用法:

(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

实例1:将把 empnametitle.txt 文件中的雇员名称和职位合并到一行内,字段之间以分号:
分隔,并且在管理者的名称前面加上一个星号
*

[root@localhost ~]# cat emp.txt               

John Doe

CEO

Jason Smith

IT Manager

Raj Reddy

Sysadmin

Anand Ram

Developer

Jane Miller

Sales Manager

[root@localhost ~]# cat label.sed 

N

s/\n/:/

/Manager/!b end

s/^/*/

:end

p

[root@localhost ~]# sed -nf label.sed emp.txt   

John Doe:CEO

*Jason Smith:IT Manager

Raj Reddy:Sysadmin

Anand Ram:Developer

*Jane Miller:Sales Manager

t命令的格式和b命令是一样的:

[address]t[label]

它表示的是如果满足address的话,sed脚本就会根据t命令指示的标签进行流程转移。命令 t 的作用是,如果前面的命令执行成功,那么就跳转到 t 指定的标签处,继续往下执行
后续命令。 否则,仍然继续正常的执行流程。

下面也给出一个例子:

s/pattern/replacement/ t break command :break

实例2:将把 empnametitle.txt 文件中的雇员名称和职位合并到一行内,字段之间以分号:
分隔,并且在管理者的名称前面加上三个星号
*

[root@localhost ~]# cat emp.txt 

John Doe

CEO

Jason Smith

IT Manager

Raj Reddy

Sysadmin

Anand Ram

Developer

Jane Miller

Sales Manager

[root@localhost ~]# cat t.label 

h;n;H;x    #此处等同于N命令的作用效果

s/\n/:/

:repeat

/Manager/s/^/*/

/\*\*\*/!t repeat

p

[root@localhost ~]# sed -nf t.label emp.txt 

John Doe:CEO

***Jason Smith:IT Manager

Raj Reddy:Sysadmin

Anand Ram:Developer

***Jane Miller:Sales Manager

注意:分支命令b用于无条件转移,测试命令t用于有条件转移,他们只有当替换命令改变当前行时才会执行。

四、sed实战

实例1:使用sed模拟出tac的功能(倒序输出)

[root@localhost ~]# cat num 1 2 3 4 5 [root@localhost ~]# sed '1!G;h;$!d' num 5 4 3 2 1

实例2:行列转换

[root@localhost ~]# cat num     1     2     3     4     5 [root@localhost ~]# sed -ne 'H;${x;s/\n/ /g;p}' num  1 2 3 4 5

实例3:行列转换100之内数字求和

[root@localhost ~]# seq 100|sed -ne 'H;${x;s/\n/+/g;s/^+//p}'|bc 5050

实例4:追加匹配行到行尾

[root@localhost ~]# cat file 0 1 hello 2 3 hello 4 5 [root@localhost ~]# sed -e '/hello/{H;d}' -e '$G' file  0 2 4 5 1 hello 3 hello

实例5:在文件中每行后面加空白行

[root@localhost ~]# cat num 1 2 3 4 5 [root@localhost ~]# sed 'G' num 1 2 3 4 5 [root@localhost ~]#

实例6:保留文件最后一行

[root@localhost ~]# sed '$!d' num 5

实例7:保留文件的每一行后方有且只有一个空白行

[root@bash ~]# cat /etc/issue \S Kernel \r on an \m Geek Young Learning Services [root@bash ~]# sed '/^$/d;G' /etc/issue \S Kernel \r on an \m Geek Young Learning Services

实例8:保留奇数行

[root@localhost ~]# cat num 1 2 3 4 5 [root@localhost ~]# sed 'n;d' num 1 3 5

实例9:去基名

[root@localhost ~]# echo '/etc/sysconfig/network-scripts'|sed -r 's@^.*/([^/]+)/?$@\1@' network-scripts

实例10:取目录名

[root@localhost ~]# echo '/etc/sysconfig/network-scripts/'|sed -r 's@[^/]+/?$@@' /etc/sysconfig/

例11:引用系统变量

[root@localhost ~]# a=2

[root@localhost ~]# cat num

a

b

c

[root@localhost ~]# sed -n ''$a',3p' num

b

c

总结:sed高级用法灵活多变,使用前要搞清楚模式空间的内容,以及sed命令的执行过程,到此sed用法就结束了,要想灵活使用sed还得多练。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/14369.html