中级Sed:在Linux环境中操纵文本流

sed流编辑器可用于以最小量的指令执行复杂的编辑操作。 sed的自动化性质使其非常适合在脚本和后台处理中使用。本文将继续在Usi的基础

介绍

sed流编辑器是一个强大的编辑工具,可以用很少的输入进行扫描更改。 在我们以前的文章中美战略经济对话,我们讨论了使用SED编辑文本的基础知识

本文将通过检查一些更高级的主题继续我们的介绍。

提供多个编辑序列

有很多实例,你可能希望同时传递多个命令sed。 有几种方法可以实现这一点。

如果你还没有手头的文件,让我们从上次重新创建我们的环境,以便我们有一些文件操纵:

cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .
echo "this is the song that never ends
yes, it goes on and on, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because..." > annoying.txt

由于sed通过标准的输入和输出操作,当然,我们可以通过管道将不同的调用串联到sed(记住要转义“&”,因为它意味着“完全匹配模式”到sed):

sed 's/and/\&/' annoying.txt | sed 's/people/horses/'
this is the song that never ends
yes, it goes on & on, my friend
some horses started singing it
not knowing what it was
& they'll continue singing it forever
just because...

这工作,但它创建不必要的开销,多次调用sed,占用更多的空间,并没有利用sed的内置功能。

我们可以通过在每个命令之前使用“-e”选项将各种命令串起来。 这是如何重写上述命令:

sed -e 's/and/\&/' -e 's/people/horses/' annoying.txt

将命令串在一起的另一种方法是使用分号字符(;)来分隔不同的命令。 这与上面的工作相同,但是“-e”不是必需的。

sed 's/and/\&/;s/people/horses/' annoying.txt

注意当使用“-e”结构时,你需要为不同的命令单独的单引号组。 但是,当使用分号分隔命令时,所有命令都只放在一个单引号命令字符串中。

虽然这两种表示多个命令的方式是有用的,但有时仍需要先前的管道技术。

考虑“=”运算符。 此操作符在每个现有行之间的新行上插入行号。 输出如下所示:

sed '=' annoying.txt
1
this is the song that never ends
2
yes, it goes on and on, my friend
3
some people started singing it
4
not knowing what it was
5
and they'll continue singing it forever
6
just because...

如果我们想通过修改文本改变编号的格式,但是,我们看到的东西不能正常工作。

为了演示,我们将引入“G”命令,默认情况下,在每行之间输入空行(这实际上是更复杂,但我们以后将了解)。

sed 'G' annoying.txt
this is the song that never ends

yes, it goes on and on, my friend

some people started singing it

not knowing what it was

and they'll continue singing it forever

just because...

如果我们组合这两个命令,我们可能期望每个常规线和线号线之间有一个空格。 但是,我们得到了不同的东西:

sed '=;G' annoying.txt
1
this is the song that never ends

2
yes, it goes on and on, my friend

3
some people started singing it

4
not knowing what it was

. . .
. . .

这是因为“=”运算符直接修改实际的输出流。 这意味着您不能使用结果进行更多编辑。

我们可以通过使用两个sed调用来解决这个问题,将第一个sed修改视为第二个文本的简单流:

sed '=' annoying.txt | sed 'G'
1

this is the song that never ends

2

yes, it goes on and on, my friend

3

some people started singing it
. . .
. . .

我们现在看到我们期望的结果。 请记住,一些命令操作像这样,特别是如果你在一起串多个命令,输出不同于你的期望。

高级寻址

sed的可寻址命令的一个优点是正则表达式可以用作选择标准。 这意味着我们不限于对已知的行值进行操作,就像我们之前学到的:

sed '1,3s/.*/Hello/' annoying.txt
Hello
Hello
Hello
not knowing what it was
and they'll continue singing it forever
just because...

相反,我们可以使用正则表达式来仅匹配包含特定模式的行。 我们通过在给出命令字符串之前将我们的匹配模式放在两个正斜杠(/)之间来实现:

sed '/singing/s/it/& loudly/' annoying.txt
this is the song that never ends
yes, it goes on and on, my friend
some people started singing it loudly
not knowing what it was
and they'll continue singing it loudly forever
just because...

在这个例子中,我们已经在包含字符串“singing”的每一行的第一个“it”之后放置了“响亮”。 请注意,第二行和第四行未更改,因为它们与模式不匹配。

用于寻址的表达式可以是任意复杂的。 这在执行命令时提供了很大的灵活性。

这不是一个复杂的例子,但它演示使用正则表达式生成其他命令的地址。 这匹配任何空行(行的开始紧跟着行的结尾),并将它们传递给delete命令:

sed '/^$/d' GPL-3
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007
 Copyright (C) 2007 Free Software Foundation, Inc. 
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.
                            Preamble
  The GNU General Public License is a free, copyleft license for
. . .
. . .

请记住,正则表达式也可以在范围的任一边使用。

例如,我们可以通过发出以下命令删除从只包含单词“START”的行开始直到读为“END”的行:

sed '/^START$/,/^END$/d' inputfile

需要注意的是,这将删除从第一个“开始”到第一个“结束”的一切,然后重新开始删除,如果它遇到另一个“开始”标记。

如果我们想反转一个地址(在任何不匹配模式的行上操作),我们可以使用感叹号或bang(!)来跟随模式。

例如,我们可以使用以下命令删除任何非空行(不是非常有用,但只是一个例子):

sed '/^$/!d' GPL-3




地址不需要是要反转的复杂表达式。 反转在常规编号地址上也是一样。

使用保持缓冲区

提高sed能力的一个功能执行多行感知编辑是所谓的“保持缓冲区”。 保持缓冲区是可以由某些命令修改的临时存储区域。

这个额外缓冲区的存在意味着我们可以在处理其他行时存储行,然后根据需要对每个缓冲区进行操作。

以下是影响保持缓冲区的命令:

  • H:将当前模式缓冲区(目前我们相匹配的线和工作)进保留缓冲区(这会擦除保持缓冲区以前的内容)。
  • H:附加当前模式缓冲区为当前保持模式的结束,由新线(\ n)的字符分隔。
  • G:将当前持有缓冲区到当前模式缓冲区。 先前的模式缓冲器被擦除。
  • G:附加当前保持模式当前的模式缓冲区的末尾,由新线(\ n)的字符分隔。
  • X:交换当前格局和保持缓冲区。

保持缓冲器的内容不能被操作,直到以某种方式被移动到模式缓冲器。

让我们用一个复杂的例子来探索这个想法。

这是一个如何连接相邻行的程序示例(sed实际上有一个内置命令,它将为我们处理很多这样的命令。“N”命令将下一行追加到当前行。做事情的困难的方式,虽然为了练习):

sed -n '1~2h;2~2{H;g;s/\n/ /;p}' annoying.txt
this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they'll continue singing it forever just because...

这是很多消化,所以让我们把它分解。

首先要注意的是,“-n”选项用于禁止自动打印。 Sed只会打印,当我们具体告诉它。

脚本的第一部分是“1〜2h”。 开始是地址规范,意思是在第一行上,然后在每隔一行(每个奇数行)上执行后续操作。 “h”部分是将匹配的行复制到保留缓冲区的命令。

命令的下半部分更复杂。 同样,它从地址规范开始。 这次,它指的是偶数线(与第一命令相反)。

命令的其余部分用大括号括起来。 这意味着其余的命令将继承刚刚指定的地址。 没有大括号,只有“H”命令将继承地址,其余命令将在每一行上执行。

“H”命令将新行字符,后跟当前模式缓冲区复制到当前保持模式的末尾。

然后用“g”命令将该保持模式(奇数行,后面跟着新行字符,然后是偶数行)复制回模式缓冲器(替换先前的模式缓冲器)。

接下来,用空格替换换行符,并使用“p”命令打印该行。

如果你好奇,使用“N”命令,如上所述,会大大缩短。 此命令将产生与我们刚刚看到的相同的结果:

sed -n 'N;s/\n/ /p' annoying.txt
this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they'll continue singing it forever just because...

使用Sed脚本

当您开始使用更复杂的命令时,在文本编辑器中组合它们可能会有所帮助。 如果您有大量的命令要应用于单个目标,这也是有帮助的。

例如,如果你喜欢用纯文本来编写消息,但是你需要在使用文本之前执行一组标准化的格式化,一个sed脚本将是有用的。

而不是键入每一组sed调用,您可以将命令放在脚本中并将其作为sed的参数提供。 sed脚本只是一个原始sed命令的列表(通常在单引号字符之间的部分)。

例如:

s/this/that/g
s/snow/rain/g
1,5s/pinecone/apricot/g

然后我们可以使用以下语法调用该文件:

sed -f sedScriptName fileToEdit

这允许您将所有编辑内容放在一个文件中,并在需要符合您创建的格式的任意文本文件上执行。

结论

在本文中,我们添加了一些深入我们对sed的理解。

Sed的命令并不总是容易理解,它通常需要一些实际的实验来了解它们的效用。 因此,建议您在实际需要之前练习操作文本。 有一个终极目标,并试图实现它只使用sed。

希望,到这一点,你开始理解的权力,一个适当的精通sed可以给你。 你的使用越智能,你从长远来看要做的工作越少。

使用Sed编辑 - 第1条

使用Sed编辑 - 第2条

作者:Justin Ellingwood