前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >sed 保持空间命令之 g、G 的执行逻辑

sed 保持空间命令之 g、G 的执行逻辑

作者头像
用户1148526
发布2024-07-13 09:03:24
660
发布2024-07-13 09:03:24
举报
文章被收录于专栏:Hadoop数据仓库

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

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

命令 g(get)把保持空间的内容复制到模式空间。假定当前模式空间内容为“line 1”,保持空间内容为“line 2”,执行命令 g 之后,模式空间内容变为“line 2”,保持空间内容仍然为“line 2”。

1. 将保持空间的内容复制到模式空间

示例文本 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/{g;p}' empnametitle.txt
Jason Smith
Jane Miller
#

本例中:

  • /Manager/!h 的作用是如果模式空间内容不包含关键字 Manager,那么就把它复制到保持空间。
  • /Manager/{g;p} 的作用是如果模式空间内容包含关键字 Manager,则把保持空间的内容复制到模式空间中,然后打印出来。

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

循环次数

模式空间

保持空间

操作

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 Smith\nIT Manager 空

Jason Smith Jason Smith\nIT Manager IT Manager IT Manager

H => x => p Jason Smith\nIT 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 Miller\n Sales Manager

Jane Miller Jane Miller \nSales Manager Sales Manager

H => x => p Jane Miller\n Sales Manager

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

创建内容如下的脚本文件 g.sed

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

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

代码语言:javascript
复制
chmod u+x g.sed

执行脚本

代码语言:javascript
复制
#./g.sed empnametitle.txt
Jason Smith
Jane Miller
#

大写 G 命令把当前保持空间的内容作为新行追加到模式空间中。模式空间的内容不会被覆盖,该命令在模式空间后面加上换行符 \n,然后把保持空间内容追加进去。G 和 g 的用法类似于 H 和 h,小写命令替换原来的内容,大写命令追加原来的内容。

假定当前模式空间内容为“line 1”,保持空间内容为“line 2”,命令 G 执行后,模式空间内容变为“line 1\nline 2”,同时保持空间内容不变,仍然为“line 2”。

2. 在每行后面加一空行

代码语言:javascript
复制
#echo -e "line1\nline2\nline3" | sed 'G'
line1

line2

line3

#

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/{x;G;s/\n/:/;p}' empnametitle.txt
Jason Smith:IT Manager
Jane Miller:Sales Manager
#

本例中:

  • /Manager/!h 的作用是如果模式空间内容不包含关键字 Manager,那么就把它复制到保持空间。
  • /Manager/{x;G;s/\n/:/;p} 的作用是如果模式空间包含 Manager,那么:
    • x 交换模式空间和保持空间的内容。
    • G 把保持空间的内容追加到模式空间。
    • s/\n/:/ 在模式空间中,把换行符替换为冒号。
    • 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 Jason Smith Jason Smith\nIT Manager Jason Smith:IT Manager 空

Jason Smith IT Manager IT Manager IT Manager IT Manager

x => G => s/\n/:/ => p Jason Smith:IT 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 Jane Miller Jane Miller\nSales Manager Jane Miller:Sales Manager

Jane Miller Sales Manager Sales Manager Sales Manager

x => G => s/\n/:/ => p Jane Miller:Sales Manager

注意:如果舍去命令 x,即使用 /Manager/{G;s/\n/:/;p},那么结果会由“雇员职位: 雇员名称”变成”雇员名称: 雇员职位”。

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

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

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

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

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

执行脚本

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

4. 用 sed 加行号并模拟 tac

cat -n 可以加行号,tac 可以按行反转输出,例如:

代码语言:javascript
复制
#echo -e "line1\nline2\nline3\nline4\nline5" | cat -n | tac
     5	line5
     4	line4
     3	line3
     2	line2
     1	line1
#

用 sed 也可以达到相同的效果:

代码语言:javascript
复制
#echo -e "line1\nline2\nline3\nline4\nline5" | sed '=' | sed 'N;s/\n/  /g;s/^/     /g;' | sed -n '1!G;h;$p'
     5  line5
     4  line4
     3  line3
     2  line2
     1  line1
#

第一个 sed 命令用于在每行前面加行号:

代码语言:javascript
复制
#echo -e "line1\nline2\nline3\nline4\nline5" | sed '='
1
line1
2
line2
3
line3
4
line4
5
line5
#

第二个 sed 命令将行号与正文拼成一行,并对标 cat -n 的输出添加相应的空格:

代码语言:javascript
复制
#echo -e "line1\nline2\nline3\nline4\nline5" | sed '=' | sed 'N;s/\n/  /g;s/^/     /g;'
     1  line1
     2  line2
     3  line3
     4  line4
     5  line5
#

N 命令将下一行添加到模式空间中,结果是当前读入行和用 N 命令添加的下一行拼成“一行”:

代码语言:javascript
复制
1\nline1
2\nline2
3\nline3
4\nline4
5\nline5

s/\n/ /g;s/^/ /g; 命令将 \n 替换成两个空格,并在行头添加四个空格,为的是让输出和 cat -n 完全一样。

最后的 sed -n '1!G;h;$p' 命令模拟 tac 反转输出行,这个命令的工作原理是:

  1. 1!G:对于不是第一行的每一行,将保持空间的内容追加到模式空间。由于在第一行之前没有内容在保持空间中,所以这一行对第一行没有影响。
  2. h:将模式空间的内容复制到保持空间中。
  3. $p:在文件的最后一行,打印模式空间的内容。

完整的执行流程如下表所示(为简化演示,没显示行头的空格)。

循环次数

模式空间

保持空间

操作

1

1 line1 1 line1 空

\n 1 line1 1 line1

h =>

2

2 line2 2 line2\n1 line1 2 line2\n1 line1 空

1 line1 1 line1 2 line2\n1 line1 2 line2\n1 line1

G => h =>

3

3 line3 3 line3\n2 line2\n1 line1 3 line3\n2 line2\n1 line1 空

2 line2\n1 line1 2 line2\n1 line1 3 line3\n2 line2\n1 line1 3 line3\n2 line2\n1 line1

G => h =>

4

4 line4 4 line4\n3 line3\n2 line2\n1 line1 4 line4\n3 line3\n2 line2\n1 line1 空

3 line3\n2 line2\n1 line1 3 line3\n2 line2\n1 line1 4 line4\n3 line3\n2 line2\n1 line1 4 line4\n3 line3\n2 line2\n1 line1

G => h =>

5

5 line5 5 line5\n4 line4\n3 line3\n2 line2\n1 line1 5 line5\n4 line4\n3 line3\n2 line2\n1 line1

4 line4\n3 line3\n2 line2\n1 line1 4 line4\n3 line3\n2 line2\n1 line1 5 line5\n4 line4\n3 line3\n2 line2\n1 line1

G => h => p 5 line5\n4 line4\n3 line3\n2 line2\n1 line1

但是需要注意,这种方法实际上是在文件处理完成后才输出反转的内容,而不是在读取文件时逐行反转。对于真正的逐行反向输出,应该考虑使用 tac 或者编写一个小的脚本(如使用 awk、perl 或 bash)来实现。例如,使用 awk 实现逐行反向输出的脚本可能如下所示:

代码语言:javascript
复制
awk '{lines[NR] = $0} END {for (i=NR; i>0; i--) print lines[i]}' filename

这个 awk 脚本将文件的每一行存储在数组 lines 中,然后在文件处理完成后,从数组的末尾开始向前遍历并打印每一行,从而实现反向输出的效果。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 将保持空间的内容复制到模式空间
  • 2. 在每行后面加一空行
  • 3. 模式空间到保持空间的逐行复制、隔行匹配、并行打印
  • 4. 用 sed 加行号并模拟 tac
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档