删除包含某些字符串的行和以下行


70

我用这个

cat foo.txt | sed '/bar/d'

删除bar文件中包含字符串的行。

但是,我想删除这些行以及紧接其后的行。最好的sedawk或者其他工具,在MINGW32的可用。

这是我可以grep使用的-A-B打印匹配行以及匹配行之前/之后的行的一种反向方式。

有什么简单的方法可以实现吗?


2
仅供参考:我正在分析条目为两条线的日志。因此,我想找到一个与模式匹配的条目,并删除它以及下一行。因此,我不需要处理连续的匹配行,但是无论如何,感谢您的回答的完整性!
jakub.g 2012年

Answers:


74

如果您具有GNU sed(因此是非嵌入式Linux或Cygwin):

sed '/bar/,+1 d'

如果您有bar连续两行,这将删除第二行而不进行分析。例如,如果您有一个三行文件bar/ bar/ foo,则该foo行将保留。


1
长度为+1 :)在我的特定示例中,我没有连续的bars,所以这个很容易记住。
jakub.g 2012年

11
sed '/bar/d'如果您只想“删除包含某些字符串的行”而不是下一个。
AJP

如果要在数学运算后删除所有行,那么?
潘迪

1
@Pandya有所不同。您可以使用例如sed '/math/q'
Gilles

1
@AK如果您只想删除匹配的行,则更加简单:sed '/bar/d'
Gilles

16

如果bar可能连续出现,您可以执行以下操作:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

可以通过更改上面的2行和要删除的行数(包括匹配的行)来更改删除多于2行的内容。

如果没有,可以sed使用@MichaelRollins的解决方案轻松完成,或者:

sed '/bar/,/^/d' < infile > outfile

AWK解决方案的另一个优点是可以替换/bar//bar|baz|whatever/。在sed那种语法似乎不起作用。
jakub.g 2012年

@ jakub.g,我有GNU sed(现在是v4.4)。不确定其他人。我所知道的是,默认情况下它使用“基本”正则表达式语法,这就是为什么您的示例不起作用的原因。要实现您想要的功能,您可以在每条垂直线前加一个反斜杠,也可以要求sed使用“扩展”正则表达式。此处有更多信息:gnu.org/software/sed/manual/html_node/…。请注意,这也适用grep。这是我自己的工作示例:echo $'0a\n1b\n2c' | sed '/0a\|1b/d'
Victor Yarema

12

我不精通sed,但是用awk很容易做到:

awk '/bar/{getline;next} 1' foo.txt 

awk脚本的内容为:对于包含bar的行,获取下一行(getline),然后跳过所有后续处理(下一步)。末尾的1个图案将打印剩余的行。

更新资料

如评论中所指出,上述解决方案不适用于Continuous bar。这是一个经过修订的解决方案,其中考虑到了这一点:

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

现在,我们继续阅读以跳过所有/ bar /行。


1
要复制grep -A100%,您还需要bar正确处理任意数量的连续行(通过删除整个块和之后的1行)。
2012年

7

您将需要利用sed的脚本功能来完成此任务。

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

样本数据:

$ cat sample1.txt 
foo
bar
biz
baz
buz

“ N”命令将输入​​的下一行追加到模式空间中。这与模式匹配中的行(/ bar /)相结合,将成为您要删除的行。然后,您可以使用“ d”命令正常删除。


如何在控制台中输入换行符?还是仅脚本?
jakub.g 2012年

@ jakub.g:使用GNU sed:sed -e '/bar/{N;d}' sample1.txt
Cyrus

2

如果在比赛之后立即删除任何行,则您的sed程序将不得不考虑连续比赛。换句话说,如果您删除匹配后也匹配的行,则可能也应该删除该行。

它的实现方式非常简单-但是您必须稍稍落后一些。

printf %s\\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'

0
6
11
12
15

它通过交换读入的每一行的保持空间和模式空间来工作,因此每次都可以将最后一行与当前行进行比较。因此,当sed读取一行时,它将交换其缓冲区的内容-而前一行则是其编辑缓冲区的内容,而当前行则置于保留空间中。

因此,请sed检查上一行是否与匹配match,如果!找不到,则运行该{函数}中的两个表达式。sedg等通过覆盖模式空间保留空间-这意味着当前行是随后用双手保持和模式空间-然后它会//检查是否有一个匹配它最近正则表达式编译- match-如果没有match它被p冲洗。

这意味着如果没有一个线仅印刷紧邻的前一行不。它还放弃了对es 序列的任何不必要的交换。match matchmatch

如果您想要一个可以删除之后任意数量行的版本,match则需要做更多的工作:

printf %s\\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

...将5替换为您要删除的行数(包括匹配的行) ...


1
2
3
4
12
13
14
21
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.