使用Sed Stream编辑器在Linux中处理文本的基本知识

sed流编辑器是一个非交互式行编辑器,可用于对文本流或文件执行强大的编辑操作。学习使用sed井将允许您以极大的速度和灵活性来转换文本。

介绍

sed流编辑器是对来自标准输入或文件的信息执行编辑操作的文本编辑器。 Sed以逐行方式并以非交互方式编辑。

这意味着您将在调用命令时进行所有编辑决策,而sed将自动执行指令。 这可能看起来很混乱或不直观,但它是一种非常强大和快速的方式来转换文本。

本教程将介绍一些基本操作,并向您介绍操作此编辑器所需的语法。 你几乎肯定不会替换您的常规文本编辑器与sed,但它可能会成为一个欢迎添加到您的文本编辑工具箱。

基本用法

通常,sed对从标准输入或从文件读取的文本流进行操作。

这意味着您可以将另一个命令的输出直接发送到sed进行编辑,或者您可以处理已创建的文件。

你也应该知道sed输出一切默认标准输出。 这意味着,除非重定向,sed会将其输出打印到屏幕,而不是保存在文件中。

基本用法是:

sed [options] commands [file-to-edit]

我们将一些文件复制到我们的主目录以练习一些编辑。

cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .

让我们使用sed来查看我们复制的BSD许可证文件的内容。

因为我们知道sed默认将其结果发送到屏幕上,所以我们可以通过传递它没有编辑命令来将其用作文件读取器。 让我们试试:

sed '' BSD
Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
...
...

这是因为单引号包含我们传递给sed的编辑命令。 我们没有通过,所以它只是打印每一行它接收到标准输出。

我们将演示如何通过将“cat”命令的输出管道到sed中以产生相同的结果来使用标准输入。

cat BSD | sed ''
Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
. . .
. . .

正如你所看到的,我们可以操作文本或文本流(当管道输出带有“|”字符时)也很容易。

打印线

在前面的示例中,我们看到输入传入sed而没有任何操作会将结果直接打印到标准输出。

我们现在将探索sed的显式“print”命令,它是使用单引号中的“p”字符指定的。

sed 'p' BSD
Copyright (c) The Regents of the University of California.
Copyright (c) The Regents of the University of California.
All rights reserved.
All rights reserved.


Redistribution and use in source and binary forms, with or without
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
modification, are permitted provided that the following conditions
are met:
are met:
. . .
. . .

你可以看到sed现在打印了每一行两次。 这是因为它自动打印每一行,然后我们告诉它使用“p”命令显式打印。

如果你检查输出如何有第一行两次,第二行两次,等等,你会看到sed逐行操作。 它接受一行,对其进行操作,并在下一行上重复处理之前输出结果文本。

我们可以通过传递“-n”选项来清除结果,sed禁止自动打印:

sed -n 'p' BSD
Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
. . .
. . .

我们现在回到每行打印一次。

地址范围

到目前为止的例子几乎不能被认为是编辑(除非我们想打印每行两次)。 让我们修改输出只有sed打印第一行。

sed -n '1p' BSD
Copyright (c) The Regents of the University of California.
通过在打印命令之前放置数字“1”,我们告诉sed要操作的行号。 我们可以轻松地打印五行(不要忘记“-n”)。
sed -n '1,5p' BSD
Copyright (c) The Regents of the University of California.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
我们刚刚给了一个地址范围sed。 如果我们给sed一个地址,它将只执行那些行上的命令。 在这个例子中,我们告诉sed打印第1行到第5行。我们可以通过给出第一个地址,然后使用偏移量来告诉sed有多少额外的行需要以不同的方式指定:
sed -n '1,+4p' BSD

这将导致相同的输出,因为我们已经告诉sed从第1行开始,然后在接下来的4行操作。

如果我们要打印每隔一行,我们可以指定“〜”字符后的间隔。 以下行将打印从第1行开始的每隔一行:

sed -n '1~2p' BSD
Copyright (c) The Regents of the University of California.

modification, are permitted provided that the following conditions
1. Redistributions of source code must retain the above copyright
2. Redistributions in binary form must reproduce the above copyright
   documentation and/or other materials provided with the distribution.
   may be used to endorse or promote products derived from this software
. . .
. . .

删除文本

我们可以轻松地执行文本删除,我们以前通过将“p”命令更改为“d”命令来指定文本打印。

我们不再需要“-n”命令,因为使用delete命令,sed将打印所有未删除的内容,这将帮助我们看到发生了什么。

我们可以修改上一节中的最后一个命令,使其从第一个开始删除每隔一行。 其结果是,我们应该给每一个我们没有给出最后的时间线。

sed '1~2d' BSD
All rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
   notice, this list of conditions and the following disclaimer.
   notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
   without specific prior written permission.
. . .
. . .

重要的是要注意,我们的源文件不受影响。 它仍然完好无损。 编辑将输出到我们的屏幕。

如果我们要保存我们的编辑,我们可以将标准输出重定向到一个文件,如:

sed '1~2d' BSD > everyother.txt

如果我们用cat打开文件,我们将看到我们以前在屏幕上看到的相同的输出。 默认情况下Sed不会编辑源文件为了我们的安全。

我们可以通过传递sed“-i”选项来改变这种行为,这意味着就地执行编辑。 这将编辑源文件。

让我们通过就地编辑我们刚刚创建的“everyother.txt”文件来尝试。 让我们通过再次删除每隔一行来进一步减少文件:

sed -i '1~2d' everyother.txt

如果您再次使用猫,您可以看到该文件已被编辑。

如前面提到的,“-i”选项可以是危险 幸运的是,sed让我们能够在编辑之前创建一个备份文件。

要在编辑之前创建备份文件,请在“-i”选项后直接添加备份扩展名:

sed -i.bak '1~2d' everyother.txt

这将创建一个具有“.bak”扩展名的备份文件,然后就地编辑常规文件。

替换文本

也许sed最知名的用法是替换文本。 Sed能够使用正则表达式搜索文本模式,然后替换找到的文本。

点击这里了解正则表达式如果需要的话。

在最简单的形式中,可以使用以下语法将一个字更改为另一个字:

's/old_word/new_word/'

“s”是替换命令。 三个斜杠(/)用于分隔不同的文本字段。 如果字段更有帮助,您可以使用其他字符来分隔字段。

例如,如果我们尝试更改网站名称,使用另一个分隔符将有所帮助,因为网址包含斜杠。 我们将在示例中使用echo管道:

echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'
http://www.example.org/home.html

不要忘记最后的分隔符,否则sed会报错。

echo "http://www.example.com/index.html" | sed 's_com/index_org/home'
sed: -e expression #1, char 22: unterminated `s' command

让我们创建一个文件来实现我们的替换:

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

现在让我们用“向前”代替表达式“on”。

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

你可以在这里看到一些值得注意的事情。 首先,是我们正在替换模式,而不是字。 “歌曲”内的“开”变为“向前”。

另外要注意的是,在第2行,第二个“on”没有改变为“forward”。

这是因为默认情况下,“s”命令在一行中的第一个匹配操作,然后移动到下一行。

要使sed替换每个“on”的每个实例而不是每行上的第一个实例,我们可以向substitute命令传递一个可选标志。

我们将通过将替换命令放置在替换集之后为替换命令提供“g”标志。

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

现在替代命令正在改变每个实例。

如果我们希望改变“的”二审在每一行的SED发现,那么我们就可以用数字“2”,而不是“G”。

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

如果我们只想看看哪些行被替换,我们可以再次使用“-n”选项来禁止自动打印。

然后,我们可以将“p”标志传递给替换命令,以打印发生替换的行。

sed -n 's/on/forward/2p' annoying.text
yes, it goes on and forward, my friend

正如你所看到的,我们可以在命令结尾处组合这些标志。

如果我们想让搜索进程忽略大小写,我们可以通过它的“i”标志。

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

引用匹配的文本

如果我们希望使用正则表达式找到更复杂的模式,我们有许多不同的方法来引用替换文本中的匹配模式。

例如,如果我们想从行的开头匹配到“at”,我们可以使用表达式:

sed 's/^.*at/REPLACED/' annoying.txt
REPLACED never ends
yes, it goes on and on, my friend
some people started singing it
REPLACED it was
and they'll continue singing it forever
just because...

您可以看到通配符表达式从行的开头匹配到“at”的最后一个实例。

由于您不知道在搜索字符串中匹配的确切短语,您可以使用“&”字符表示替换字符串中匹配的文本。

此示例显示如何在匹配的文本周围放置括号:

sed 's/^.*at/(&)/' 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...

引用匹配文本的更灵活方式是使用转义括号将匹配文本的部分分组。

标有括号的每组搜索文本都可以使用转义的引用号引用。 例如,第一个括号组可以用“\ 1”引用,第二个用“\ 2”引用,依此类推。

在这个例子中,我们将切换每行的前两个词:

sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/' annoying.txt
is this the song that never ends
yes, goes it on and on, my friend
people some started singing it
knowing not what it was
they and'll continue singing it forever
because just...

正如你所看到的,结果并不完美。 例如,第二行跳过第一个单词,因为它有一个未列在我们的字符集中的字符。 同样,它将“他们”作为第五行中的两个词。

让我们改进正则表达式以更准确:

sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' annoying.txt
is this the song that never ends
it yes, goes on and on, my friend
people some started singing it
knowing not what it was
they'll and continue singing it forever
because... just

这比上次更好。 这将标点符号与相关字词组合在一起。

注意我们如何重复括号内的表达式(一次没有“*”字符,然后一次)。 这是因为“*”字符匹配在零或多次之前的字符集。

这意味着与通配符的匹配将被认为是“匹配”,即使未找到模式。

为了确保至少找到一次,我们必须匹配一次,而不使用通配符,然后再使用通配符。

结论

我们已经涵盖了sed的一些基础知识。 您应该能够看到如何使用正确构造的sed命令快速转换文本文档。

在本系列的下一篇文章中,我们将介绍sed的一些更高级的功能。

使用Sed编辑 - 第1条

使用Sed编辑 - 第2条

作者:Justin Ellingwood