103

我对 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.

这六个命令真的让我很困惑。

4

3 回答 3

132

当 sed 逐行读取文件时,当前已读取的行被插入到模式缓冲区(模式空间)中。模式缓冲区就像临时缓冲区,即存储当前信息的暂存器。当您告诉 sed 打印时,它会打印模式缓冲区。

保持缓冲区/保持空间就像一个长期存储,这样您就可以捕获一些东西,存储它并在 sed 处理另一行时重新使用它。您不直接处理保持空间,而是需要将其复制或附加到模式空间,如果您想对其进行操作。例如, print 命令p仅打印模式空间。同样,s对模式空间进行操作。

这是一个例子:

sed -n '1!G;h;$p'

(-n 选项禁止自动打印行)

这里有三个命令1!Gh$p1!G有一个地址,1(第一行),但这意味着!该命令将在除第一行之外的任何地方执行。另一方面,只会在最后一行执行。所以会发生这样的事情:$p

  1. 第一行被读取并自动插入到模式空间中
  2. 在第一行,不执行第一个命令;h将第一行复制到保留空间中。
  3. 现在第二行替换了模式空间中的任何内容
  4. 在第二行,首先我们执行G,将保持缓冲区的内容附加到模式缓冲区,并用换行符分隔。模式空间现在包含第二行、换行符和第一行。
  5. 然后,hcommand 将模式缓冲区的连接内容插入到保存空间中,该空间现在保存反转的第 2 行和第 1 行。
  6. 我们继续进行第三行——转到上面的第 (3) 点。

最后,在读取最后一行并将保持空间(包含所有前面的行以相反的顺序)附加到模式空间后,模式空间打印为p. 正如您已经猜到的那样,上面的内容完全符合tac命令的作用——反向打印文件。

于 2012-10-11T07:30:21.870 回答
21

@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在输出中出现两次。)

解释:

  1. -n除非明确打印,否则禁用输出
  2. 第一次匹配,找到该行并将其Host:放入保持缓冲区(h)
  3. 第二次匹配,找到下一个 Info: 行,但首先用保持缓冲区交换 (x) 模式缓冲区中的当前行,并打印 (p) 该Host:行,然后重新交换 (x) 并打印 (p) Info: 行。

是的,这是一个简单的示例,但我怀疑这是一个常见问题,可以通过简单的 sed 单线快速处理。对于更复杂的任务,例如不能依赖给定的、可预测的序列的任务,awk 可能更适合。

于 2013-08-19T19:30:15.833 回答
18

尽管@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 教程也是很好的参考。

于 2017-06-05T19:54:30.420 回答