我对 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.
这六个命令真的让我很困惑。
当 sed 逐行读取文件时,当前已读取的行被插入到模式缓冲区(模式空间)中。模式缓冲区就像临时缓冲区,即存储当前信息的暂存器。当您告诉 sed 打印时,它会打印模式缓冲区。
保持缓冲区/保持空间就像一个长期存储,这样您就可以捕获一些东西,存储它并在 sed 处理另一行时重新使用它。您不直接处理保持空间,而是需要将其复制或附加到模式空间,如果您想对其进行操作。例如, print 命令p
仅打印模式空间。同样,s
对模式空间进行操作。
这是一个例子:
sed -n '1!G;h;$p'
(-n 选项禁止自动打印行)
这里有三个命令1!G
:h
和$p
。1!G
有一个地址,1
(第一行),但这意味着!
该命令将在除第一行之外的任何地方执行。另一方面,只会在最后一行执行。所以会发生这样的事情:$p
h
将第一行复制到保留空间中。G
,将保持缓冲区的内容附加到模式缓冲区,并用换行符分隔。模式空间现在包含第二行、换行符和第一行。h
command 将模式缓冲区的连接内容插入到保存空间中,该空间现在保存反转的第 2 行和第 1 行。最后,在读取最后一行并将保持空间(包含所有前面的行以相反的顺序)附加到模式空间后,模式空间打印为p
. 正如您已经猜到的那样,上面的内容完全符合tac
命令的作用——反向打印文件。
@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)Host:
行,然后重新交换 (x) 并打印 (p) Info: 行。是的,这是一个简单的示例,但我怀疑这是一个常见问题,可以通过简单的 sed 单线快速处理。对于更复杂的任务,例如不能依赖给定的、可预测的序列的任务,awk 可能更适合。
尽管@January 的回答和示例很好,但解释对我来说还不够。我必须搜索和学习很多东西,直到我设法了解它的sed -n '1!G;h;$p'
工作原理。所以我想为像我这样的人详细说明命令。
首先,让我们看看该命令的作用。
$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | 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\na$ 1!G;h
c c\nb\na$ 1!G;h
d d\nc\nb\na$ 1!G;h;$p
在最后一行,$p
打印d\nc\nb\na$
格式化为
d
c
b
a
如果要查看每一行的模式空间,可以添加一个l
命令。
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a
我发现观看此视频教程了解 sed 的工作原理非常有帮助,因为该人显示了如何逐步使用每个空间。第 4 个教程中提到了保持间隔,但如果您不熟悉sed
.
GNU sed 文档和Bruce Barnett 的 Sed 教程也是很好的参考。