BASH - 选择性删除

时间:2013-10-08 20:46:26

标签: bash sed

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

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

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

Guest-List 3
Guest-list 5

我有兴趣使用sed实现这一点。因为我是菜鸟,所以没有sed的其他可能的解决方案也会受到赞赏(回答时请提供详细解释,以便我可以学习):)

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

提前致谢!

3 个答案:

答案 0 :(得分:3)

您可以像这样使用fgrep

fgrep -v -f <(fgrep 'All present' -B1 file) file
Guest-List 3
Guest-list 5

答案 1 :(得分:2)

sed -n '/All present$/{s/.*//;x;d;};x;p;${x;p;}' file | sed '/^$/d'

file是您的档案。

这是here.

的改编示例

它有一个很好的解释:

  

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

     

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

     

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

答案 2 :(得分:0)

如果你在sed中使用的命令多于s,g和p(带-n)命令,那么你使用的语言结构在20世纪70年代中期发明时已经过时了。

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)数组,你不想输出,第二次打印行是不在那个数组中。简单,清晰,可维护,可扩展,......