1

我有一个看起来像这样的文件:

Guest-List 1
All present
Guest-list 2
All present
Guest-List 3
Guest-list 4
All present
Guest-list 5

我想删除包含“所有存在”的行及其标题(“所有存在”上方的行)。所需的输出将是:

Guest-List 3
Guest-list 5

我有兴趣使用 sed 来实现它。因为我是菜鸟,其他可能没有 sed 的解决方案也将不胜感激(回答时请提供详细解释,以便我学习):)

(我知道可以删除与正则表达式匹配的行,并可以将其上方的行存储到将其发送到保持缓冲区,如下所示: sed '/^.*present$/d; h' ... 然后是“g”命令会将保持缓冲区复制回模式空间......但我如何告诉 sed 也删除它?)

提前致谢!

4

3 回答 3

3

你可以fgrep这样使用:

fgrep -v -f <(fgrep 'All present' -B1 file) file
Guest-List 3
Guest-list 5
于 2013-10-08T21:03:36.973 回答
2
sed -n '/All present$/{s/.*//;x;d;};x;p;${x;p;}' file | sed '/^$/d'

file你的文件在哪里。

这是从这里改编的例子。

它有一个很好的解释:

为了删除模式之前的行,我们将每一行存储在一个称为保持空间的缓冲区中。每当模式匹配时,我们都会删除两者中存在的内容,包含当前行的模式空间,包含前一行的保持空间。

让我解释一下这个命令x;p;:这将针对每一行执行。 x用保持空间交换模式空间的内容。p打印模式空间。结果,每次,当前行都进入保持空间,前一行进入模式空间并被打印。当模式/All Present/匹配时,我们清空(s/.*//)模式空间,并与保持空间交换(x)(结果保持空间变为空)并删除(d)包含前一行的模式空间。因此,当前行和上一行在遇到 Linux 模式时会被删除。这${x;p;}是打印最后一行,如果离开,它将保留在保留空间中。

第二部分sed是删除第一个sed命令创建的空行。

于 2013-10-08T20:51:57.673 回答
0

如果您在 sed 中使用的不仅仅是 s、g 和 p(带 -n)命令,那么您使用的语言结构在 1970 年代中期 awk 被发明时就已经过时了。

sed 是在单行上进行简单替换的出色工具,其他任何事情只需使用 awk:

$ cat file
Guest-List 1
All present
Guest-list 2
All present
Guest-List 3
Guest-list 4
All present
Guest-list 5

$ awk 'NR==FNR{ if (/All present/) {skip[FNR-1]; skip[FNR]} next} !(FNR in skip)' file file
Guest-List 3
Guest-list 5

上面只解析文件两次 - 第一次创建一个以您不希望输出skip的行号 ( FNR) 命名的数组,第二次打印不在该数组中的行。简单,清晰,可维护,可扩展,......

于 2013-10-09T11:50:42.493 回答