介绍
该sed
命令是stream editor 的缩写,对来自标准输入或文件的文本执行编辑操作。sed
以非交互方式逐行编辑。
这意味着您在调用命令时做出所有编辑决定,并sed
自动执行指示。这可能看起来令人困惑或不直观,但它是一种非常强大且快速的文本转换方式,尤其是作为脚本或自动化工作流程的一部分。
本教程将介绍一些基本操作,并向您介绍操作此编辑器所需的语法。您几乎肯定永远不会用 替换您的常规文本编辑器sed
,但它可能会成为您的文本编辑工具箱中受欢迎的补充。
注意:本教程使用sed
在 Ubuntu 和其他 Linux 操作系统上找到的 GNU 版本。如果您使用的是 macOS,您将拥有具有不同选项和参数的 BSD 版本。您可以安装的GNU版本,sed
与家酿使用brew install gnu-sed
。
基本用法
sed
对从文本文件或标准输入 (STDIN) 读取的文本流进行操作。这意味着您可以将另一个命令的输出直接发送到 sed 进行编辑,或者您可以处理已经创建的文件。
您还应该注意,sed
默认情况下将所有内容输出到标准输出 (STDOUT)。这意味着,除非重定向,否则会将sed
其输出打印到屏幕而不是将其保存在文件中。
基本用法是:
- sed [options] commands [file-to-edit]
在本教程中,您将使用BSD 软件许可证的副本来试验sed
. 在 Ubuntu 上,执行以下命令将 BSD 许可证文件复制到您的主目录,以便您可以使用它:
- cd
- cp /usr/share/common-licenses/BSD .
如果您没有 BSD 许可证的本地副本,请使用以下命令自己创建一个:
- cat << 'EOF' > 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.
- 3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- EOF
让我们使用sed
来查看 BSD 许可证文件的内容。sed
默认情况下将其结果发送到屏幕,这意味着您可以通过不传递任何编辑命令将其用作文件阅读器。尝试执行以下命令:
- sed '' BSD
您将看到 BSD 许可证显示在屏幕上:
OutputCopyright (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
将收到的每一行打印到标准输出。
sed
可以使用标准输入而不是文件。将cat
命令的输出通过管道输入sed
以产生相同的结果:
- cat BSD | sed ''
您将看到文件的输出:
OutputCopyright (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
您会看到BSD
文件的每一行都打印了两次:
OutputCopyright (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
OutputCopyright (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
打印文件的第一行。执行以下命令:
- sed -n '1p' BSD
第一行打印到屏幕上:
OutputCopyright (c) The Regents of the University of California.
通过将数字1
放在打印命令之前,您告诉sed
了要操作的行号。您可以轻松打印五行(不要忘记“-n”):
- sed -n '1,5p' BSD
你会看到这个输出:
OutputCopyright (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 行进行操作。
如果要每隔一行打印一次,请在~
字符后指定间隔。以下命令BSD
从第 1 行开始打印文件中的每隔一行:
- sed -n '1~2p' BSD
这是您将看到的输出:
OutputCopyright (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
. . .
. . .
您也可以使用sed
从输出中删除文本。
删除文本
通过将p
命令更改为命令,您可以在之前指定文本打印的位置执行文本删除d
。
在这种情况下,您不再需要该-n
命令,因为sed
将打印所有未删除的内容。这将帮助您了解正在发生的事情。
修改上一节中的最后一个命令,使其
从第一行开始每隔一行删除:
- sed '1~2d' BSD
结果是您看到上次没有给出的每一行:
OutputAll 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
:
- cat everyother.txt
您会看到之前在屏幕上看到的相同输出:
OutputAll 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
命令默认不编辑源文件,但您可以通过传递-i
选项来更改此行为,这意味着“就地执行编辑”。这将改变源文件。
警告:使用此-i
开关会覆盖原始文件,因此您应谨慎使用。先在没有-i
开关的情况下执行操作,然后在获得所需内容后再次运行命令-i
,创建原始文件的备份,或将输出重定向到文件。很容易不小心用-i
开关改变了原始文件。
让我们通过everyother.txt
就地编辑您刚刚创建的文件来尝试一下。让我们通过
再次删除每隔一行来进一步缩小文件:
- sed -i '1~2d' everyother.txt
如果您使用cat
显示文件cat everyother.txt
,您将看到该文件已被编辑。
该-i
选项可能很危险。值得庆幸的是,sed
您可以在编辑之前创建备份文件。
要在编辑之前创建备份文件,请直接在“-i”选项后添加备份扩展名:
- sed -i.bak '1~2d' everyother.txt
这将创建一个带有.bak
扩展名的备份文件,然后就地编辑原始文件。
接下来,您将了解如何使用sed
来执行搜索和替换操作。
替换文本
也许最著名的用途sed
是替换文本。sed
可以使用正则表达式搜索文本模式,然后用其他内容替换找到的文本。
您可以按照在 Linux 中使用 Grep 正则表达式搜索文本模式来了解有关正则表达式的更多信息。
在最基本的形式中,您可以使用以下语法将一个单词更改为另一个单词:
's/old_word/new_word/'
的s
是替换命令。三个斜杠 ( /
) 用于分隔不同的文本字段。如果更有帮助,您可以使用其他字符来分隔字段。
例如,如果您尝试更改网站名称,使用另一个分隔符会很有帮助,因为 URL 包含斜杠。
执行以下命令以使用下划线 ( ) 字符作为分隔符打印 URLecho
并使用 修改它:sed
_
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'
这替换com/index
为org/home
. 输出显示修改后的 URL:
Outputhttp://www.example.org/home.html
不要忘记最后的分隔符,否则sed
会报错。如果您运行此命令:
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home'
你会看到这个输出:
Outputsed: -e expression #1, char 20: unterminated `s' command
让我们创建一个新文件来练习一些替换。执行以下命令以创建一个名为 的新文本文件song.txt
:
- 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..." > song.txt
现在让我们来代替表达on
用forward
。使用以下命令:
- sed 's/on/forward/' song.txt
输出如下所示:
Outputthis 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...
您可以在这里看到一些值得注意的事情。首先,是sed
替换的模式,而不是单词。该on
范围内song
更改为forward
。
另一件要注意的事情是在第 2 行,第二个on
没有更改为forward
.
这是因为默认情况下,该s
命令对一行中的第一个匹配项进行操作,然后移动到下一行。要sed
替换每行的每个实例on
而不是第一个实例,您必须将可选标志传递给替换命令。
通过将g
标志放在替换集之后,为替换命令提供标志:
- sed 's/on/forward/g' song.txt
你会看到这个输出:
Outputthis 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' song.txt
这次其他行保持不变,因为它们没有第二次出现:
Outputthis 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' song.txt
更改后的行打印到屏幕上:
Outputyes, it goes on and forward, my friend
如您所见,您可以组合命令末尾的标志。
如果您希望搜索过程忽略大小写,您可以将“i”标志传递给它。
- sed 's/SINGING/saying/i' song.txt
这是您将看到的输出:
Outputthis 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/' song.txt
你会看到这个输出:
OutputREPLACED 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/(&)/' song.txt
你会看到这个输出:
Output(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]*\)/ /' song.txt
你会看到这个输出:
Outputis 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...
如您所见,结果并不完美。例如,第二行跳过第一个单词,因为它有一个未在我们的字符集中列出的字符。同样,它they'll
在第五行中将其视为两个单词。
让我们改进正则表达式以使其更准确:
- sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/ /' song.txt
你会看到这个输出:
Outputis 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 命令快速转换文本文档。