• 本页内容

48. 删除多行中的第一行(D 命令)


正如我们之前讨论的,小写 d 命令删除当前模式空间,将下一行从输入文件读取到模式空间,中止其余的 sed 命令并再次开始循环。

大写的 D 命令删除后不会将下一行读取到模式空间,也不会完全清除模式缓冲区(除非只有一行)。相反,它执行以下操作:

  • 删除部分模式空间,直到遇到换行符(\n)。
  • 中止剩余的 sed 命令并从头开始对模式缓冲区中的剩余内容执行命令。

考虑以下文件,其中每个标题的注释都包含在 @@ 之间。 请注意,在某些情况下,此注释也会跨越界限。 例如 @Information Technology officer@ 跨越两行。

创建以下示例文件。

$ vi empnametitle-with-comment.txt
John Doe
CEO @Chief Executive Officer@
Jason Smith
IT Manager @Information Technology
Officer@
Raj Reddy
Sysadmin @System Administrator@
Anand Ram
Developer @Senior
Programmer@
Jane Miller
Sales Manager @Sales
Manager@

我们的目标是从此文件中删除这些注释。 这可以按如下所示完成。

$ sed -e '/@/{N;/@.*@/{s/@.*@//;P;D}}' empnametitle-with-comment.txt
John Doe
CEO
Jason Smith
IT Manager
Raj Reddy
Sysadmin
Anand Ram
Developer
Jane Miller
Sales Manager

您还可以将其保存在 sed 脚本文件中并执行它,如下所示。

$ vi D-upper.sed
#!/bin/sed -f
/@/ {
N
/@.*@/ {s/@.*@//;P;D }
}

$ chmod u+x D-upper.sed

$ ./D-upper.sed empnametitle-with-comment.txt

在上面的例子中:

  • /@/ {—— 这是外循环。 sed 查找任何包含 @ 符号的行。 如果找到一个,它就会执行其余的逻辑。如果没有,它会读取下一行。 例如,让我们以第 4 行为例,它是 "@Information Technology"(注释跨越多个列,也转到第 5 行)。第 4 行有一个 @ 符号,因此执行其余命令。
  • N —— 从输入文件中获取下一行并将其附加到模式空间。 例如,这将读取第 5 行 "Officer@",并将其附加到模式空间。 因此,模式空间将包含 "@Information Technology\nOfficer@"
  • /@.*@/ —— 搜索模式空间是否具有模式 "@.*@",这意味着 @@ 之间包含的任何内容。该表达式对于当前模式空间成立,因此进入下一步。
  • s/@.*@//;P;D —— 这将替换整个文本 "@Information Technology\nOfficer@"(基本上它会删除该文本)。 P 打印该行的第一部分。D删除模式空间的其余内容。逻辑又从上往下继续。