sed中"保持空间"和"模式空间"的概念

Che*_*nQi 75 linux sed

我对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.
Run Code Online (Sandbox Code Playgroud)

这六个命令真让我迷惑.

Jan*_*ary 98

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

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

这是一个例子:

sed -n '1!G;h;$p'
Run Code Online (Sandbox Code Playgroud)

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

这里有三个命令:1!G,h$p.1!G有一个地址,1(第一行),但!该命令将被执行到处手段,但在第一行上.$p另一方面,只会在最后一行执行.那么会发生什么:

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

最后,在读取完最后一行并且将保持空间(以相反顺序包含所有前面的行)附加到模式空间后,将打印模式空间p.正如您所猜到的,上面完全按照tac命令执行操作 - 反向打印文件.

  • G 和 h 选项是否像“剪切和附加”一样工作??它看起来不像“复制和附加”操作。 (3认同)

小智 15

@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
Run Code Online (Sandbox Code Playgroud)

对我来说,使用主机名和相应的信息行获取行的awk脚本将比我能用sed做的更多:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt
Run Code Online (Sandbox Code Playgroud)

输出看起来像:

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!!
Run Code Online (Sandbox Code Playgroud)

(注意sed在输出中出现两次.)

以上解释:

  1. -n禁用输出,除非明确打印
  2. 第一次匹配,查找并将Host:行放入保持缓冲区(h)
  3. 第二匹配,找到下一个信息:线,但第一交流(x)的在图案缓冲电流线与保持缓冲器,并打印(p)的主机:线,然后重新交换(x)和打印(P)的信息:线.

是的,这是一个简单的例子,但我怀疑这是一个常见的问题,很快就被一个简单的sed单行程处理.对于更复杂的任务,例如您不能依赖于给定的可预测序列的任务,awk可能更适合.

  • 如果给定主机后面有两个 Info 行,则 @JensJenson 希望两个 Info 行前面都有一个 Info 行。我想我会相应地编辑答案。Pithikos,那么 grep 就不够了。 (3认同)
  • 在这种情况下,尽管您可以只使用 grep:`grep 'Host\|Info'` (2认同)
  • @JensJenson,相当于sed代码的`awk`也很短:`awk'/ Host:/ {hold = $ 0}; / Info / {打印保留;打印;}'myfile.txt` (2认同)

San*_*Lee 10

虽然@ 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
Run Code Online (Sandbox Code Playgroud)

它像tac命令一样反转输入.

sed逐行读取,让我们看看patten空间和每行的保持空间会发生什么.当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
Run Code Online (Sandbox Code Playgroud)

在最后一行,$p打印d\nc\nb\na$格式为

d
c
b
a
Run Code Online (Sandbox Code Playgroud)

如果要查看每行的模式空间,可以添加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
Run Code Online (Sandbox Code Playgroud)

我发现观看这个视频教程非常有帮助了解sed是如何工作的,因为这个人展示了如何逐步使用每个空间.保持间隔在第4节教程中引用,但如果您不熟悉,我建议您观看所有视频sed.

此外GNU SED文件布鲁斯·巴内特的桑达教程是非常好的参考.

  • 我认为,除非我们添加一些东西,否则所有实际用途的容纳空间都是空的,这也很有帮助。 (2认同)
  • 你可以做 `printf "%s\n" {a..d}` 而不是 `echo {a..d} | tr ' '\n'` (2认同)