sed 保持空间命令之 H 的执行逻辑

2024-07-08 10:43:32 浏览数 (3)

sed 有两个内置的存储空间:

  • 模式空间:该空间是 sed 内置的一个缓冲区,是 sed 执行的正常流程中,暂存当前处理行的空间。每处理完一行都会清空模式空间再读取下一行。模式空间初始为空。
  • 保持空间:保持空间是另外一个缓冲区,用来存放临时数据,以便在后续处理中使用。与模式空间不同,保持空间的内容不会在循环中被删除。不能在保持空间上执行普通的 sed 命令。保持空间初始为一个换行符。

大写 H 命令表示把模式空间的内容追加到保持空间,追加不会覆盖保持空间的内容。当向初始保持空间追加内容时,因为保持空间初始内容为一个换行符 n,所以直接把模式空间内容追加进来。当保持空间已经有内容时,H 命令在当前保持空间内容后面加上换行符 n,然后再把模式空间内容追加进来。

假定目前模式空间内容为“line 1”,保持空间内容为“line 2”。那么执行命令 H 后,模式空间的内容没有改变,仍然为“line 1”,保持空间的内容则变为“line2nline 1”。

以下是一些使用 H 命令的例子。

1. 追加文本到保持空间

代码语言:javascript复制
#echo "Hello World" | sed -n 'H; x; p;'

Hello World
#

这个 sed 脚本会将模式空间的内容追加到保持空间,然后交换模式空间和保持空间的内容,使得保持空间的内容被打印出来。从输出可以看到比原始文本多了第一行的空行(保持空间的初始换行符)。

2. 追加并分隔文本到保持空间

代码语言:javascript复制
#echo -e "HellonWorld" | sed -n 'H; x; $!d; x; p'
World
#

这个 sed 脚本会在追加文本到保持空间的同时追加一个换行符。完整的执行流程如下表所示。

循环次数

模式空间

保持空间

操作

1

Hello Hello nHello 空

n nHello Hello Hello

H => x => d =>

2

World World HellonWorld World

Hello HellonWorld World HellonWorld

H => x => x => p World

注意,第一行的 $!d 命令会清空模式空间,并启动下一个循环,这实际上会导致跳过其后的 x; p 命令,直到最后一行。

3. 模式空间到保持空间的逐行复制、隔行匹配、分行打印

示例文本 empnametitle.txt 的内容如下:

代码语言:javascript复制
John Doe
CEO
Jason Smith
IT Manager
Raj Reddy
Sysadmin
Anand Ram
Developer
Jane Miller
Sales Manager

在这个文件中,每个员工的姓名和职位位于连续的两行内。下面的命令在不同行上分别打印管理者的名称和职位。

代码语言:javascript复制
#sed -n -e '/Manager/!h' -e '/Manager/{H;x;p}' empnametitle.txt
Jason Smith
IT Manager
Jane Miller
Sales Manager
#

这个例子中:

  • /Manager/!h 是将模式空间中不包含关键字 Manager 的内容复制到保持空间。这样保持空间的内容可能会是雇员名称或职位,但不是 Manager。
  • /Manager/{H;x;p} 的作用是如果模式空间内容包含关键字 Manager,那么命令 H 把模式空间的内容(也就是管理者的职位)作为新行追加到保持空间,所以保持空间内容会变为“雇员名称n职位”(职位包含关键字Manager)。然后命令 x 交换模式空间和保持空间的内容,随后命令 p 打印模式空间的内容。

完整的执行流程如下表所示。

循环次数

模式空间

保持空间

操作

1

John Doe John Doe 空

n John Doe John Doe

h =>

2

CEO CEO 空

John Doe CEO CEO

h =>

3

Jason Smith Jason Smith 空

CEO Jason Smith Jason Smith

h =>

4

IT Manager IT Manager Jason SmithnIT Manager 空

Jason Smith Jason SmithnIT Manager IT Manager IT Manager

H => x => p Jason SmithnIT Manager =>

5

Raj Reddy Raj Reddy 空

IT Manager Raj Reddy Raj Reddy

h =>

6

Sysadmin Sysadmin 空

Raj Reddy Sysadmin Sysadmin

h =>

7

Anand Ram Anand Ram 空

Sysadmin Anand Ram Anand Ram

h =>

8

Developer Developer 空

Anand Ram Developer Developer

h =>

9

Jane Miller Jane Miller 空

Developer Jane Miller Jane Miller

h =>

10

Sales Manager Sales Manager Jane Millern Sales Manager

Jane Miller Jane Miller nSales Manager Sales Manager

H => x => p Jane Millern Sales Manager

也可以把命令保存到 sed 脚本中执行:

创建内容如下的脚本文件 H-upper.sed

代码语言:javascript复制
#!/bin/sed -nf
/Manager/!h
/Manager/{H;x;p}

修改脚本文件的模式为可执行

代码语言:javascript复制
chmod u x H-upper.sed

执行脚本

代码语言:javascript复制
#./H-upper.sed empnametitle.txt
Jason Smith
IT Manager
Jane Miller
Sales Manager
#

如果想把雇员名称和职位显示在同一行,并以冒号分开,那么只需稍微修改一下即可:

代码语言:javascript复制
#sed -n -e '/Manager/!h' -e '/Manager/{H;x;s/n/:/g;p}' empnametitle.txt
Jason Smith:IT Manager
Jane Miller:Sales Manager
#

这个例子除了在第二个 -e 后面的命令中加入了替换命令之外,和前面的例子一样。H、x 和 p 都完成和之前相同的操作。在交换模式空间和保持空间之后,命令 s 把换行符 n 替换为分冒号,然后打印出来。

同样可以把上面命令保存到 sed 脚本中执行:

创建内容如下的脚本文件 H1-upper.sed

代码语言:javascript复制
#!/bin/sed -nf
/Manager/!h
/Manager/{H;x;s/n/:/g;p}

修改脚本文件的模式为可执行

代码语言:javascript复制
chmod u x H1-upper.sed

执行脚本

代码语言:javascript复制
#./H1-upper.sed empnametitle.txt 
Jason Smith:IT Manager
Jane Miller:Sales Manager
#

0 人点赞