中级赛德在 Linux 环境中操作文本流

介绍

sed流编辑器是一个强大的编辑工具,可以通过很少的输入进行广泛的更改,在上一篇关于sed的文章中,您探讨了使用sed来编辑文本的基本知识(https://www.digitalocean.com/community/articles/the-basics-of-using-the-sed-stream-editor-to-manipulate-text-in-linux)。

本文将通过探索一些更先进的主题来继续您的介绍。

<$>[注] :本教程使用在Ubuntu和其他Linux操作系统上发现的GNU版本的sed。如果你使用macOS,你将有BSD版本,其中有不同的选项和论点。你可以使用brew install gnu-sed安装sed的GNU版本。

要完成本教程,你需要一些文件来操纵,你应该从第一个教程。

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

此外,您将在本教程中使用 GPL 3 许可证,因此您也可以复制该文件:

1cp /usr/share/common-licenses/GPL-3 .

如果你没有它,你可以用curl下载它:

1curl -o GPL-3 https://www.gnu.org/licenses/gpl-3.0.txt

现在你有这些文件,你会使用sed来探索多个命令。

提供多重编辑序列

有很少的例子,你可能想同时传递多个命令到sed

由于sed通过标准输入和输出进行操作,您可以通过管道连接不同的调用来sed。 执行此命令以替换and一词为andpeople一词为horses:

1sed 's/and/\&/' song.txt | sed 's/people/horses/'

请注意,你需要逃避&,因为它意味着完整的匹配模式sed):

您将看到以下输出:

1[secondary_label Output]
2this is the song that never ends
3yes, it goes on & on, my friend
4some horses started singing it
5not knowing what it was
6& they'll continue singing it forever
7just because...

这样做是有效的,但它会创建不必要的过度调用sed,需要更多的打字,并且不会利用sed的内置功能。

您可以通过在每个命令前使用-e选项来将各种命令串到sed

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

另一种方法是使用半列字符(;)来分离不同的命令。

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

请注意,当使用e构造时,您需要为不同的命令分开单引文组。然而,当用半列分开命令时,所有命令都放置在一个单引文命令字符串中。

考虑 = 运算器. 该运算器在每个现有线之间的新线上插入一行号码。

1sed '=' song.txt

以下是你会看到的Ouput:

 1[secondary_label Output]
 21
 3this is the song that never ends
 42
 5yes, it goes on and on, my friend
 63
 7some people started singing it
 84
 9not knowing what it was
105
11and they'll continue singing it forever
126
13just because...

但是,如果您想通过修改文本来更改编号的格式,则会发现情况不像预期的那样工作。

为了演示,让我们看看G命令,该命令默认情况下在每个行之间输入一个空行(这实际上更为复杂,但您将稍后探索):

1sed 'G' song.txt

这里是结果:

 1[secondary_label Output]
 2this is the song that never ends
 3
 4yes, it goes on and on, my friend
 5
 6some people started singing it
 7
 8not knowing what it was
 9
10and they'll continue singing it forever
11
12just because...

如果您将这两个命令结合起来,您可能会预计每个 常规行和行数行之间的间隙:

1sed '=;G' song.txt

但是,你得到了一些不同的东西:

 1[secondary_label Output]
 21
 3this is the song that never ends
 4
 52
 6yes, it goes on and on, my friend
 7
 83
 9some people started singing it
10
114
12not knowing what it was
13
14. . .
15. . .

这是因为 = 操作器直接修改实际输出流,这意味着您无法使用结果进行更多编辑。

您可以通过使用两个sed调用来绕过这一点,将第一个sed修改视为第二个简单的文本流:

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

现在你可以看到你所期望的结果:

 1[secondary_label Output]
 21
 3
 4this is the song that never ends
 5
 62
 7
 8yes, it goes on and on, my friend
 9
103
11
12some people started singing it
13. . .
14. . .

请记住,一些命令是这样操作的,特别是如果您正在一起串行多个命令,并且输出与您预期的不同。

先进的对话

sed的可地址命令的优点之一是可以使用常规表达式作为选择标准,这意味着您不受限于以已知的行值操作,就像您之前所看到的那样:

1sed '1,3s/.*/Hello/' song.txt
1[secondary_label Output]
2Hello
3Hello
4Hello
5not knowing what it was
6and they'll continue singing it forever
7just because...

相反,您可以使用常规表达式仅匹配包含特定模式的行. 要做到这一点,在给出命令字符串之前,将匹配模式放置在两个前进切片之间(/):

1sed '/singing/s/it/& loudly/' song.txt
1[secondary_label Output]
2this is the song that never ends
3yes, it goes on and on, my friend
4some people started singing it loudly
5not knowing what it was
6and they'll continue singing it loudly forever
7just because...

在本示例中,您在包含字符串唱歌的每个行上,在的第一个出现后,放置了无声。注意第二和第四行是未变的,因为它们不匹配模式。

地址表达式可以是任意复杂的,这为执行命令提供了很大的灵活性。

这不是一个复杂的例子,但它展示了使用常规表达式来生成其他命令的地址。下面的命令匹配任何空行(一行的开始随后立即由一行结束),并将其传递到删除命令:

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

这是你会看到的结果:

 1[secondary_label Output]
 2                  GNU GENERAL PUBLIC LICENSE
 3                      Version 3, 29 June 2007
 4Copyright (C) 2007 Free Software Foundation, Inc. 
 5Everyone is permitted to copy and distribute verbatim copies
 6of this license document, but changing it is not allowed.
 7                          Preamble
 8The GNU General Public License is a free, copyleft license for
 9. . .
10. . .

请记住,您也可以在范围的两侧使用常规表达式,例如,您可以删除从仅包含开始字的行开始的行,直到读取终止字的行。

例如,创建一个名为inputfile的文件:

1echo "This is an input file
2START
3this is the text we don't want
4END
5This is additional text" > inputfile

现在使用sed删除STARTEND之间的内容:

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

您将看到以下输出:

1This is an input file
2This is additional text

值得注意的是,这将从第一个开始到第一个结束删除一切,然后如果遇到另一个开始标记,重新启动删除。

如果您想要逆转一个地址(在任何 not 匹配模式的行上操作),您可以跟随该模式,使用呼叫点(!)。

例如,您可以使用以下命令删除任何字符串 not 是空的(不是非常有用的,但只是一个示例):

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

这导致一个大的空输出,因为sed仍然打印了线条默认情况下:

1[secondary_label Output]

地址不需要是一个复杂的表达式来逆转,逆转也同样适用于常规编号的地址。

使用保留缓冲器

增加sed执行多行知情编辑的能力的一个功能是所谓的保留缓冲器

这种额外缓冲器的存在意味着您可以在其他线上工作时存储线条,然后根据需要在每个缓冲器上操作。

以下是影响持有缓冲器的命令:

  • h:将当前模式缓冲器(您当前匹配和工作的线)复制到持有缓冲器中(从而删除持有缓冲器的以前内容)。
  • H:将当前模式缓冲器附加到当前持有模式的末尾,以新线(\n)字符分开
  • g:将当前持有缓冲器复制到当前模式缓冲器中。

持有缓冲器的内容不能操作,直到它以一种或另一种方式被移动到模式缓冲器。

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

这是如何加入邻近线路的程序示例(‘sed’实际上有一个内置的命令,将为我们做很多事情。

1sed -n '1~2h;2~2{H;g;s/\n/ /;p}' song.txt

以下是你会看到的输出:

1[secondary_label Output]
2this is the song that never ends yes, it goes on and on, my friend
3some people started singing it not knowing what it was
4and they'll continue singing it forever just because...

这是很多要消化的,所以让我们打破它。

首先要注意的是,使用n选项来抑制自动打印,sed只会在您明确表示时打印。

指令的第一部分是1\~2h。开始是一个地址规格,意思是在第一行执行后续操作,然后在之后的每一个线上(每个单独的编号线)。

命令的下半部分更为复杂. 再次,它以地址规格开始. 这一次,它是指正数的行(相反的第一个命令)。

该命令的其余部分被封装在包裹中,这意味着其余的命令将继承刚刚指定的地址,如果没有包裹,只有H命令将继承该地址,其余的命令将在每个行上执行。

H命令将一个新行字符,然后是当前模式缓冲,复制到当前持有模式的末尾。

此持有模式(一个奇怪的编号线,然后是新行字符,然后是均匀的编号线)随后被复制回模式缓冲器(取代以前的模式缓冲器)用g命令。

接下来,新行字符被一个空格取代,并用p命令打印了行。

如果你有好奇心,使用N命令会大大缩短这一点,下面的命令会产生你刚刚看到的相同的结果:

1sed -n 'N;s/\n/ /p' song.txt

使用脚本

随着您开始使用更复杂的命令,在文本编辑器中编写这些命令可能有帮助,如果您有大量的命令,您想应用到单个目标,这也是有用的。

例如,如果您想用简单的文本编写消息,但需要在使用文本之前执行一组标准化格式化,则有用的是sed脚本。

相反,你可以将每组sed命令输入到脚本中,并将其作为一个对sed的参数。

要尝试,创建一个名为sed_script的新文件,其中包含以下内容:

1echo "s/this/that/g
2s/people/horses/g
31,5s/it/that/g" > sed_script

保存文件并离开编辑器。

现在通过使用-f交换机来告诉sed使用该文件:

1sed -f sed_script song.txt

结果将是这样的:

1[secondary_label Output]
2that is the song that never ends
3yes, that goes on and on, my friend
4some horses started singing that
5not knowing what that was
6and they'll continue singing that forever
7just because...

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

结论

首先,Sed的命令并不总是容易理解的,通常需要一些实际的实验来了解它们的实用性,因此,建议您在实际需要之前练习操纵文本。

希望在这一点上,你开始理解sed的正确掌握能给你的力量.你与sed的舒适度越高,长期来说,你将不得不做得越少。

Published At
Categories with 技术
comments powered by Disqus