sed 中的“保留空间”和“模式空间”的概念
- 2024-11-06 08:35:00
- admin 原创
- 38
问题描述:
我对 sed 中的两个概念感到困惑:保留空间和模式空间。有人能帮忙解释一下吗?
以下是该手册的片段:
h H Copy/append pattern space to hold space. g G Copy/append hold space to pattern space. n N Read/append the next line of input into the pattern space.
这六个命令确实让我困惑。
解决方案 1:
当 sed 逐行读取文件时,当前已读取的行将插入到模式缓冲区(模式空间)中。模式缓冲区就像临时缓冲区,是存储当前信息的暂存器。当您告诉 sed 打印时,它会打印模式缓冲区。
保持缓冲区/保持空间就像一个长期存储,这样您就可以捕获某些内容,将其存储起来,并在 sed 处理另一行时重新使用它。您不能直接处理保持空间,而是需要将其复制或附加到模式空间,如果您想对其进行处理。例如,print 命令p
仅打印模式空间。同样,s
对模式空间进行操作。
以下是一个例子:
sed -n '1!G;h;$p'
(-n 选项禁止自动打印行)
这里有三个命令:1!G
,h
和$p
。1!G
有一个地址,1
(第一行),但!
意味着该命令将在第一行以外$p
的所有地方执行。另一方面,只会在最后一行执行。所以发生的事情是这样的:
读取第一行并自动插入到模式空间中
在第一行,第一个命令不执行;
h
将第一行复制到保存空间。现在第二行替换了模式空间中的所有内容
在第二行,我们首先执行
G
,将保留缓冲区的内容附加到模式缓冲区,并用换行符分隔。模式空间现在包含第二行、换行符和第一行。然后,
h
命令将模式缓冲区的连接内容插入到保持空间中,该保持空间现在保存了两条和一条反转的线。我们继续第三行——转到上面的点 (3)。
最后,在读取最后一行并将保留空间(包含所有先前的行,顺序相反)附加到模式空间后,模式空间将使用 打印p
。正如您所猜测的,上面的操作与tac
命令完全相同 - 反向打印文件。
解决方案 2:
@Ed Morton:我不同意你的观点。我发现,sed
想出一种优雅的多行 grepping 方法非常有用且简单(一旦你理解了模式和保留缓冲区的概念)。
例如,让我们拿一个包含主机名和有关每个主机的一些信息的文本文件,其中有很多我不关心的垃圾。
Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
对我来说,使用 awk 脚本来获取包含主机名和相应行的数据info
比使用 sed 所能做的要多一些:
sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt
输出如下:
Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!
(请注意,Host: foo1
在输出中出现了两次。)
解释:
-n
禁用输出,除非明确打印第一个匹配,找到并将该
Host:
行放入保持缓冲区 (h)第二次匹配,找到下一个 Info: 行,但首先将模式缓冲区中的当前行与保持缓冲区交换(x),并打印(p)该
Host:
行,然后重新交换(x)并打印(p)Info: 行。
是的,这是一个过于简单的例子,但我怀疑这是一个常见问题,只需使用简单的 sed 单行命令即可快速解决。对于更复杂的任务(例如,您不能依赖给定的可预测序列的任务),awk 可能更适合。
解决方案 3:
虽然@January的回答和例子都很好,但对我来说解释得还不够。我不得不搜索和学习很多东西,直到我设法理解它到底是如何sed -n '1!G;h;$p'
工作的。所以我想为像我这样的人详细说明一下这个命令。
首先,让我们看看该命令的作用。
$ echo {a..d} | tr ' ' '
' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '
' | sed -n '1!G;h;$p'
d
c
b
a
它像命令一样反转输入tac
。
sed
逐行读取,因此让我们看看每行模式空间和保持空间上发生了什么。当h
命令将模式空间的内容复制到保持空间时,两个空间都具有相同的文本。
Read line Pattern Space / Hold Space Command executed
-----------------------------------------------------------
a a$ h
b b
a$ 1!G;h
c c
b
a$ 1!G;h
d d
c
b
a$ 1!G;h;$p
在最后一行,$p
打印`d
c
b
a$`格式为
d
c
b
a
如果想要查看每行的模式空间,可以添加一个l
命令。
$ echo {a..d} | tr ' ' '
' | sed -n '1!G;h;l;$p'
a$
b
a$
c
b
a$
d
c
b
a$
d
c
b
a
我发现观看这个视频教程《了解 sed 的工作原理》非常有帮助,因为这个家伙一步一步地展示了如何使用每个空格。第 4 个教程中提到了保持空格,但如果您不熟悉,我建议您观看所有视频sed
。
GNU sed 文档和Bruce Barnett 的 Sed 教程也是非常好的参考资料。
解决方案 4:
这是我今天刚遇到的一个现实问题的简单示例。我有一个数据库转储文件,该文件为制表符分隔值文件,每行一条记录,字段用双引号括起来,字段之间用制表符分隔。
不幸的是,转储中的某些文本字段嵌入了回车符,这导致我导入这些 TSV 文件的数据库失败。回车符行总是看起来像这样:
"60888" "1" "characters" "JLA [Aquaman; Aztek; Flash [Wally West]; Green Arrow [Connor Hawke]; Green Lantern [Kyle Rayner]; Martian Manhunter; Superman [Clark Kent; Kal-El]];^M
Jemm Son of Saturn; Metron; Plastic Man; Robin [Tim Drake];^M
Injustice Gang [Circe; Doctor Light [Arthur Light]; Joker; Lex Luthor; Mirror Master [Evan McCulloch]; Ocean Master]"
(^M
显示回车符的位置。)
使用这个简单的 sed 脚本,我能够连接各行并删除回车符:
/
/s/
//g
/[^"]$/{
H;
s/
/ /g;
}
/"$/{
H;
s/^.*$//;
x;
s/
//g;
p;
}
我尝试了“只使用 awk”的建议,当我想“这实际上比使用保持缓冲区更复杂”时,我已经对脚本有了一点了解。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件