如何grep -v并排除比赛后的下一行?


15

如何为匹配grep regex的每一行过滤出2行?
这是我的最低要求:

SomeTestAAAA
EndTest
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestAABC
EndTest
SomeTestACDF
EndTest

显然我尝试了例如grep -vA 1 SomeTestAA不起作用。

所需的输出是:

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

grep -v'SomeTextAA'| uniq?
DarkHeart

Answers:


14

您可以grep-P(PCRE)一起使用:

grep -P -A 1 'SomeTest(?!AA)' file.txt

(?!AA)是零宽度负先行图案,确保没有AAafter SomeTest

测试:

$ grep -P -A 1 'SomeTest(?!AA)' file.txt 
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

点的转义字符是什么?像Some.Test.AA?
Behrooz

1
@Behrooz的逃生点\.这样grep -P -A 1 'SomeTest\.(?!AA)' file.txtgrep -P -A 1 'SomeTest(?!\.AA)' file.txt
heemayl

这在特定情况下有效,因为在OP中,采样行成对出现,SomeTest*\nEndTest因此您实际上对grep所有匹配的行执行ping操作,SomeTest*SomeTestAA在匹配之后却不+一行上下文。在输入中添加更多行(例如,foobar在每EndTest行之后添加一行),然后重试。
don_crissti

1
@don_crissti是的,我已经解决了这个问题。
Behrooz

@Behrooz-希望与我们分享您的工作方式,并在您的问题下回答我的评论?
don_crissti

4

这是可与任意输入sed配合使用的解决方案(-n即不进行自动打印):

sed -n '/SomeTestAA/!p          # if line doesn't match, print it
: m                             # label m
//{                             # if line matches
$!{                             # and if it's not the last line
n                               # empty pattern space and read in the next line
b m                             # branch to label m (so n is repeated until a
}                               # line that's read in no longer matches) but
}                               # nothing is printed
' infile

所以输入像

SomeTestAAXX
SomeTestAAYY
+ one line
SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestAABC
+ another line
SomeTestTHREE
EndTest
SomeTestAA
+ yet another line

跑步

sed -n -e '/SomeTestAA/!p;: m' -e '//{' -e '$!{' -e 'n;b m' -e '}' -e'}' infile

输出

SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestTHREE
EndTest

也就是说,它会完全删除grep -A1 SomeTestAA infile将选择的行:

SomeTestAAXX
SomeTestAAYY
+ one line
--
SomeTestAABC
+ another line
--
SomeTestAA
+ yet another line

有趣。我没意识到那//匹配/SomeTestAA/。我认为,在这种情况下,它将与否定的表达式匹配:/SomeTestAA/!。(+1)
Peter.O 2015年

@ Peter.O-谢谢!不,按照规范,空的RE应该始终与上一条命令中使用的最后RE相匹配;这!不是RE的一部分,而是sed一回事。
don_crissti

3

将多行区域视为单个记录的东西可能会更好。这里有一个sgrep我还没有使用太多。

还有awk,您可以在其中将输入记录分隔符和输出记录分隔符设置为任意值。

pat="^SomeTestAA"
awk  'BEGIN{ RS=ORS="\nEndTest\n"} !/'"$pat/" foo

大多数awk程序都用单引号引起来,但是我在结尾处更改为双引号,以便$pat可以扩展shell变量。


awk -vpat="^SomeTestAA" -vRS="\nEndTest\n" 'BEGIN{ ORS=RS } $0 !~ pat' file
Peter.O 2015年

3

一种选择是使用pERL compatible regular e上的表达grep

pcregrep -Mv 'SomeTestAA.*\n' file

该选项-M允许模式匹配多于一行。


1
@don_crissti这两行都将被删除。OP的规范不涵盖这种情况。
jimmij 2015年

很明显,OP样本和问题并未涵盖此类情况,我只是好奇地知道这是如何工作的(我对pcre不熟悉),因为匹配的奇数行连续行,这是可行的(它删除了上下文行也是如此),并且匹配的偶数行连续偶数行将失败(此后不会删除上下文行)。
don_crissti

鉴于(GNU)grep已经支持PCRE(通过-P选件),使用的好处是pcregrep什么?
arielf

@arielf grep不支持该-M选项。
jimmij 2015年

1

您可以使用GNU sedd命令删除一行,并为其加上前缀/pat/,+N以选择与模式匹配的行以及随后的N行。在您的情况下,N = 1,因为您只想删除匹配行之后的单个后续行:

sed -e '/SomeTestAAAA/,+1d'

1

使用标准sed

$ sed '/SomeTestAA/{ N; d; }' file
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

sed脚本解析由线输入的文件中的行,并且当线相匹配的图案SomeTestAA,两个sed编辑命令Nd被执行。该N命令将输入​​的下一行追加到模式空间(sed可以编辑的缓冲区),然后d删除模式空间并开始下一个循环。


1

尝试了下面的sed命令,它工作正常

命令

sed  '/SomeTestAA/,+1d' filename

输出

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest
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.