如果字符串匹配则删除行,下一行包含另一个字符串

时间:2014-08-08 10:32:34

标签: awk sed grep

有一个讨厌的文本操作问题,我需要删除文件中的一行,如果它包含一个字符串,但只有当下一行还包含另一个字符串时。例如,我有这些行:

john paul
george
john paul
12
john paul

我想删除任何包含' john paul'如果紧接着是包含' george'的行,那么它将返回:

george
john paul
12
john paul

不确定如何grep或sed这个。如果有人能伸出援助之手,那就太棒了!

8 个答案:

答案 0 :(得分:2)

这可能适合你(GNU sed):

sed '/john paul/{$!N;/\n.*george/!P;D}' file

如果该行包含john paul,请阅读下一行,如果该行包含george,请不要打印第一行。

N.B。如果包含george的行包含john paul,则也会对其进行检查。

答案 1 :(得分:1)

awk应该:

cat file
john paul
george
john paul
12
john paul
hans
george

awk 'f~/john paul/ && /george/ {f=$0;next} NR>1 {print f} {f=$0} END {print}' file
george
john paul
12
john paul
hans
george

如果george

,则只会删除john paul上方的名称

答案 2 :(得分:1)

awk 'NR > 1 && !(/george/ && p ~ /john paul/) { print p } { p = $0 } END { print }' file

输出:

george
john paul
12
john paul

答案 3 :(得分:1)

这是一个更通用的版本: 如果这些行匹配一个字符串而前一行恰好是“john paul”则不执行任何操作,否则,打印上一行。 (如果您只想检测^[a-zA-Z]$,请将george部分更改为george

awk '!(/^[a-zA-W]+$/ && previous ~/^john paul$/){print previous}{previous=$0}END{print}'

在你的例子中:

$> echo 'john paul
george
john paul
12
john paul' |awk '!(/^[a-zA-W]+$/ && previous ~/^john paul$/){print previous}{previous=$0}END{print}'

george
john paul
12
john paul

如果行中有一些数字,则打印前一个,否则不打印:

$> echo 'john paul
george 234
john paul
auie
john paul' |awk '!(/^[a-zA-W]+$/ && previous ~/^john paul$/){print previous}{previous=$0}END{print}'

john paul
george 234
auie
john paul

答案 4 :(得分:1)

sed 解决方案很简短:两个命令和大量注释;)

/john paul/ {
        # read the next line and append to pattern space
        N   
        # and then if we find "george" in that next line,
        # only retain the last line in the pattern space
        s/.*\n\(.*george\)/\1/
        # and finally print the pattern space,
        # as we don't use the -n option
}

您将上述内容放在某个sedscript文件中,然后运行:

sed -f sedscript your_input_file

答案 5 :(得分:0)

您可能需要将\ r \ n更改为\ n或更改为\ r \ n,除此之外应该有效:

<?php
$string = "john paul
george
john paul
12
john paul";

$string = preg_replace("#john paul\r\n(george)#i",'$1',$string);

echo $string;
?>

您还可以将文件读入变量,然后覆盖文件。

答案 6 :(得分:0)

使用GNU awk进行多字符RS:

$ gawk -vRS='^$' '{gsub(/john paul\ngeorge/,"george")}1' file
george
john paul
12
john paul

或者如果每行上的内容比您的示例输入更多,则只需将RE更改为适合并使用gensub():

$ gawk -vRS='^$' '{$0 = gensub(/[^\n]*john paul[^\n]*\n([^\n]*george[^\n]*)/,"\\1","")}1' file
george
john paul
12
john paul

答案 7 :(得分:0)

只是将一些Perl扔进混音:

perl -ne 'print $p unless /george/ && $p =~ /john paul/; $p = $_ }{ print $p' file

打印上一行,除非当前行与/george/匹配且上一行$p/john paul/匹配。将$p设置为上一行的值。 }{有效地创建了一个END块,因此在读取文件后也会打印最后一行。