使用 sed 进行文本操作
过滤器 sed 可以处理来自标准输入的文本,并将结果写入标准输出。输入可以从文件重定向,输出也可以使用 shell 的重定向功能重定向到文件。它有数百种用途,一旦你学会了 sed,如果失去它,你真的会想念它。
sed 可以追加行、删除行、更改行、重新排列行、替换文本字符串等等。使用 sed,您可以编写简单的脚本,这些脚本可以成为强大的文本操作命令。
sed 可以使用正则表达式来定义在文本行上执行哪些处理以及处理哪些行。如果您以前从未见过或使用过正则表达式,您可能需要熟悉正则表达式的基本语法。在本文中,我们使用一些正则表达式使 sed 执行一些简单的文本处理。
sed 可以在命令行中如下运行
cat sample.txt | sed -e '1,15d'
您可以 cat 文件 sample.txt 并使用管道将其输出(文本行)重定向到 sed 命令中。sed 的 -e 选项告诉它使用下一个项目作为 sed 命令。d 命令告诉 sed 删除输入流的第 1-15 行,在本例中是从 sample.txt 读取的行。文件的其余部分(如果有)将出现在标准输出(您的终端窗口)上,除非重定向到其他地方。
此外,您可以简单地将输入文件指定为命令行参数,因此上面的 sed 命令也可以写成
sed -e '1,15d' sample.txt
您还可以通过使用 [-f script-file] 选项告诉 sed 从脚本文件读取命令。
pattern1 和 pattern2 是可选的行范围。有些命令不使用模式,有些命令只使用一个模式,有些命令可以使用两个模式来指定 sed 命令可以操作的行范围,就像我们在上面的简单示例中所做的那样。
pattern1 和 pattern2 可以是数字,在这种情况下,它们被视为行号。它们也可以是由斜杠 (/) 分隔的正则表达式(/pattern/)。当使用正则表达式模式时,所有与表达式匹配的行都将通过 sed 命令进行过滤。
如果未指定模式,则 sed 命令将对输入的每一行进行操作。
!使 sed 对未包含在模式范围内的每一行进行操作。您可以将上面的示例更改为
cat sample.txt | sed -e '1,15!d'
这里有一些基本的 sed 示例。这些都可以直接从命令行运行。在将 sed 命令集成到更大的脚本之前,先在命令行上单独测试和调试它们,将为您节省大量时间,否则这些时间将花费在从运行脚本中调试命令上。
假设您有一个名为 customer.txt 的文件,其中列出了客户。对于以下示例,它包含简单的文本行,如下所示
Sam Jones Brenda Jones Carl Simon Liz Smith
让我们使用一些 sed 命令来操作此文件。例如,如果您想删除包含 Carl Simon 的行并更新您的客户文件,您可以执行以下操作
cat customer.txt | \ sed -e '/Carl Simon/d' > customer.txt
模式 /Carl Simon/ 被 sed 用作正则表达式,并匹配每一行中某处具有该模式的行。d 命令删除与该模式匹配的每一行。因此,任何包含 Carl Simon 的行都将从文件中删除。
如果您想对文本文件执行某种类型的文本替换,则 s 命令可能是您正在寻找的。它用一个文本字符串替换另一个文本字符串。我们在脚本中经常使用它。例如,如果 Sam Jones 打电话来告诉您您应该将他列为 Samuel Jones,则可以使用此命令进行更改
cat customer.txt | \ sed -e 's/Sam Jones/Samuel Jones/' > customer.txt
sed 中的 s 命令在 s 之后有三个斜杠。第一个和第二个斜杠之间的文本是您要匹配的模式。第二个和第三个斜杠之间的文本包含您要替换第一个模式的模式。如果您希望将所有 Sam 实例都替换为 Samuel(而不仅仅是 Sam Jones),则可以按如下方式重写此示例
cat customer.txt | \ sed -e 's/Sam/Samuel/' > customer.txt
append (a)、replace (c) 和 insert (i) 命令通常需要将 sed 命令指定在单独的脚本文件中。例如,假设您想在包含文本 Brenda 的行之后立即追加行 After Brenda。您可以使用 a sed 命令在那里追加文本。但是,您需要将 sed 命令放在单独的脚本文件中,因此请启动您喜欢的编辑器并创建以下 sed 命令文件
# # sed command file (# are comment lines) # # append the line 'After Brenda' # in this customer file # /Brenda/a\ After Brenda
将此脚本文件另存为 sed1.cmd。然后,要使用此脚本文件运行 sed,请使用以下语法
sed -f sed1.cmd customer.txt
您应该看到客户文件的内容,其中在 Brenda Jones 行之后添加了额外的行。模式 /Brenda/(在 sed 命令文件中)确定追加的行在输出中出现的位置。
append 命令和 insert 命令之间的区别在于文本添加的位置。对于 append 命令,文本在包含匹配项的行之后添加。对于 insert 命令,文本在包含匹配项的行之前添加。
对于那些从未使用过正则表达式的人,这里有三个正则表达式,当与 sed 结合使用时非常有用
要匹配行首,请使用 ^ 字符。
要匹配行尾,请使用 $ 字符。
要在正则表达式中匹配任意数量的字符,请使用字符 .*。 . 匹配任何单个字符,* 匹配任意数量的字符(包括零个)。
从文件中过滤掉空行
sed -e '/^$/d' your_file.txt
将名为 mycomputer 的计算机添加到 /etc/exports 中每一行的末尾
cat /etc/exports | \ sed -e 's/$/ mycomputer/' > /etc/exports
仅将名为 comp2 的计算机添加到 /etc/exports 中以 /data/ 开头的目录
cat /etc/exports | \ sed -e '/^\/data\//s/$/ comp2/' > /etc/exports
看到目录名称中使用的正斜杠如何必须使用反斜杠进行转义吗?如果没有反斜杠,sed 会将目录说明符中的正斜杠解释为 sed 命令本身的分隔符。但是,反斜杠会使 sed 命令难以阅读和理解。
删除每行中的第一个单词(包括任何前导空格和尾随空格)
cat test3.txt | sed -e 's/^ *[^ ]* //'
此示例中使用了更多的正则表达式匹配。这是它的作用。
初始的 ^ * 用于匹配行首的任意数量的空格。[^ ]* 然后匹配任意数量的非空格字符(花括号内的 ^ 反转了对空格的匹配),因此它匹配单个单词。末尾的尾随空格匹配在第一个单词末尾找到的空格。空的替换模式删除文本。
删除每行中的最后一个单词
cat test3.txt | sed -e 's/^\(.*\) .*/\1/'
此命令引入了保持缓冲区的概念。保持缓冲区用于保留匹配文本的部分,并将该文本插入到结果中。括号之间匹配文本的模式通过 \1 在替换模式中被调用。如果在匹配模式中有另一组括号,它们将在替换模式中被寻址为 \2,依此类推,对于更多组括号。最多可以指定九个保持缓冲区。在此示例中,括号中包含的模式从行首匹配到最后一个空格(括号后的空格)。
从每行中删除前导 { 和尾随 },或 }
sed -e 's/^.*{\(.*\)},*/\1/' table.txt
我将留给读者去深入研究这个正则表达式,看看它是如何运作的。请记住这一点——您越熟悉正则表达式和保持缓冲区,sed 命令就变得越强大。
Larry Richardson 为 3SI 开发气象工作站软件。他使用 C 和 C++ 为 UNIX 和 Windows 开发软件超过 13 年。现在与妻子和儿子住在佐治亚州,他喜欢在业余时间弹贝斯。