0
点赞
收藏
分享

微信扫一扫

[Meachines][Hard]Analysis

史值拥 2024-05-07 阅读 6

目录

46.读取下一行数据并附加到模式空间(命令 N)

47.打印多行模式中的第一行(命令 P)

48. 删除多行模式中的第一行(命令 D)

49.循环和分支(命令 b 和 :label 标签)

50.使用命令 t 进行循环


Sed 默认每次只处理一行数据,除非使用 H,G 或者 N 等命令创建多行模式,每行之间用换行

符分开。

本章将解释适用于多行模式的 sed 命令。

提示:在处理多行模式是,请务必牢记 ^ 只匹配该模式的开头,即最开始一行的开头,且 $

匹配该模式的结尾,即最后一行的结尾。

46.读取下一行数据并附加到模式空间(命令 N)

就像大写的命令 H G 一样,只会追加内容而不是替换内容,命令 N 从输入文件中读取下

一行并追加到模式空间,而不是替换模式空间。

前面提到过,小写命令 n 打印当前模式空间的内容,并清空模式空间,从输入文件中读取下

一行到模式空间,然后继续执行后面的命令。

大写命令 N ,不会打印模式空间内容,也不会清除模式空间内容,而是在当前模式空间内容

后加上换行符 \n, 并且从输入文件中读取下一行数据,追加到模式空间中,然后继续执行后

面的命令。

以分号分隔,打印雇员名称和职位 :

$ sed -e '{N;s/\n/:/}' empnametitle.txt

John Doe:CEO

Jason Smith:IT Manager

Raj Reddy:Sysadmin

Anand Ram:Developer

Jane Miller:Sales Manager

这个例子中 :

N 追加换行符 \n 到当前模式空间 ( 雇员名称 ) 的最后,然后从输入文件读取下一行数

据,追加进来。因此,当前模式空间内容变为 雇员名称 \n 雇员职位

s/\n/:/ 把换行符 \n 替换为分号,把分号作为雇员名称和雇员职位的分隔符

流程如下图所示 :

下面的例子将演示在打印 employee.txt 文件内容的同时,以文本方式显示每行的行号:

$ sed -e '=' employee.txt|sed '{N;s/\n/ /}'

1 101,Johnny Doe,CEO

2 102,Jason Smith,IT Manager

3 103,Raj Reddy,Sysadmin

4 104,Anand Ram,Developer

5 105,Jane Miller,Sales Manager

和之前的例子一样,命令 = 先打印行号,然后但印原始的行的内容。

这个例子中,命令 N 在当前模式空间后面加上 \n( 当前模式空间内容为行号 ), 然后读取下一行,

并追究到模式空间中。因此,模式空间内容变为 行号 \n 原始内容 。然后用 s/\n/ / 把换行符

\n 替换成空格。

47.打印多行模式中的第一行(命令 P)

目前为止,我们已经学会了三个大写的命令 (H,N,G) ,每个命令都是追加内容而不是替换内容。

现在我们来看看大写的 D P ,虽然他们的功能和小写的 d p 非常相似,但他们在多行模

式中有特殊的功能。

之前说到,小写的命令 p 打印模式空间的内容。大写的 P 也打印模式空间内容,直到它遇到

换行符 \n 下面的例子将打印所有管理者的名称 :

$ sed -n -e 'N' -e '/Manager/P' empnametitle.txt

Jason Smith

Jane Miller

48. 删除多行模式中的第一行(命令 D)

之前提到,小写命令 d 会删除模式空间内容,然后读取下一条记录到模式空间,并忽略后面

的命令,从头开始下一次循环。

大写命令 D ,既不会读取下一条记录,也不会完全清空模式空间 ( 除非模式空间内只有一行 )

它只会:

z 删除模式空间的部分内容,直到遇到换行符 \n

z 忽略后续命令,在当前模式空间中从头开始执行命令

假设有下面文件,没个雇员的职位都用 @ 包含起来作为注释。需要注意的是,有些注释是跨

行的。如 @Information Technology officer@ 就跨了两行。请先建立下面示例文件 :

$ vi empnametitle-with-commnet.txt

John Doe

CEO @Chief Executive Officer@

Jason Smith

IT Manager @Infromation Technology

Officer@

Raj Reddy

Sysadmin @System Administrator@

Anand Ram

Developer @Senior

Programmer@

Jane Miller

Sales Manager @Sales

Manager@

现在我们的目标是,去掉文件里的注释 :

$ sed -e '/@/{N;/@.*@/{s/@.*@//;P;D}}' empnametitle-with-commnet.txt

John Doe

CEO

Jason Smith

IT Manager

Raj Reddy

Sysadmin

Anand Ram

Developer

Jane Miller Sales Manager

也可把上述命令写到 sed 脚本中然后执行 :

$ vi D-upper.sed

#!/bin/sed -f

/@/{

N

/@.*@/{s/@.*@//;P;D}

}

$ chmod u+x D-upper.sed

$ ./D-upper.sed empnametitle-with-commnet.txt

John Doe

CEO

Jason Smith

IT Manager

Raj Reddy

Sysadmin

Anand Ram

Developer

Jane Miller

Sales Manager

这个例子中 :

  /@/{ 这是外传循环。 Sed 搜索包含 @ 符号的任意行,如果找到,就执行后面的命

令;如果没有找到,则读取下一行。为了便于说明,以第 4 行,即 ”@Information

Technology”( 这条注释跨了两行 ) 为例,它包含一个 @ 符合,所以后面的命令会被执

行。

N 从输入文件读取下一行,并追加到模式空间,以上面提到的那行数据为例,这

N 会读取第 5 行,即 ”Officer@” 并追加到模式空间,因此模式空间内容变

”@Informatioin Technology\nOfficer@”

  /@.*@/ 在模式空间中搜索匹配 /@.*@/ 的模式 , 即以 @ 开头和结尾的任何内容。当

前模式空间的内容匹配这个模式,因此将继续执行后面的命令。

  s/@.*@//;P;D 这个替换命令把整个 @Information Technology\nOfficer@” 替换为空

( 相当于删除 ) P 打印模式空间中的第一行,然后 D 删除模式空间中的第一行,然

后从头开始执行命令 ( 即不读取下一条记录,又返回到 /@/ 处执行命令 )

49.循环和分支(命令 b :label 标签)

使用标签和分支命令 b ,可以改变 sed 的执行流程:

  :label 定义一个标签

b lable 执行该标签后面的命令。 Sed 会跳转到该标签,然后执行后面的命令。

  注意:命令 b 后面可以不跟任何标签,这种情况下,它会直接跳到 sed 脚本的结尾 下面例子将把 empnametitle.txt 文件中的雇员名称和职位合并到一行内,字段之间以分号:

分隔,并且在管理者的名称前面加上一个星号 *

$ cat label.sed

#!/bin/sed -nf

h;n;H;x

s/\n/:/

/Manager/!b end

s/^/*/

:end

p

这个脚本中,鉴于之前的例子,你已经知道 h;n;H;x s/\n/:/ 的作用了。下面是关于分支的

操作:

z /Manager/!b end 如果行内不包含关键字 ”Manager”, 则 跳转到 ’end’ 标签,请注意,

你可以任意设置你想要的标签名称。因此,只有匹配 Manager 的雇员名称签名,

才会执行 s/^/*/( 在行首加上星号 *)

z :end 即是标签

给这个脚本加上可执行权限,然后执行:

$ chmod u+x label.sed

$ ./label.sed empnametitle.txt

John Doe:CEO

*Jason Smith:IT Manager

Raj Reddy:Sysadmin

Anand Ram:Developer

*Jane Miller:Sales Manager

个人觉得脚本里面的 h;n;H;x 可以用一个 N 替代,这样就不用使用保持空间了。

如果不使用标签,还可以: sed 'N;s/\n/:/;/Manager/s/^/\.*/' empnametitle.txt

50.使用命令 t 进行循环

命令 t 的作用是,如果前面的命令执行成功,那么就跳转到 t 指定的标签处,继续往下执行

后续命令。否则,仍然继续正常的执行流程。

下面例子将把 empnametitle.txt 文件中的雇员名称和职位合并到一行内,字段之间以分号:

分隔,并且在管理者的名称前面加上三个星号 *

提示:我们只需把前面例子中的替换命令改为 s/^/***/即可带到该目的,下面这个例子仅仅

是为了解释命令 t 是如何运行的。

$ vi lable-t.sed

#!/bin/sed -nf

h;n;H;x

s/\n/:/

: repeat

/Manager/s/^/*/

/\*\*\*/! t repeat

p

$ chmod u+x lable-t.sed

$ ./lable-t.sed empnametitle.txt

John Doe:CEO

***Jason Smith:IT Manager

Raj Reddy:Sysadmin

Anand Ram:Developer

***Jane Miller:Sales Manager

这个例子中 :

下面的代码执行循环

:repeat

/Manager/s/^/*/

/\*\*\*/! t repeat

  /Manager/s/^/*/ 如果匹配到 Manager, 在行首加上星号 *

  /\*\*\*/!t repeat 如果没有匹配到三个连续的星号 *( /\*\*\*/! 来表示 ) ,并且前面

一行的替换命令成功执行了,则跳转到名为 repeat 的标签处 ( t repeat)

  :repeat 标签

资料来源于《SedandAwk101Hacks》,大家有兴趣可以买一本,也可以关注我,我更新完它。

曾经,我花费大半月将它们跑完,现在啥都忘了,还是要常用。

只为学习交流,不为获利,侵权联系立删。

举报

相关推荐

0 条评论