使用grep,如何匹配一个模式并反转匹配另一个模式?


11

使用grep,我想选择所有与一个模式匹配但与另一个模式不匹配的行。我希望能够使用的单次调用,grep以便可以使用--after-context选项(或--before-context,或--context)。

-v在此处不可行,因为它会否定我grep使用该-e选项传递给所有模式的方式。

我想查找匹配以下内容的一行needle,而忽略匹配的ignore me行。

这是我的输入文件:

one needle ignore me
two
three
four needle
five

我想要的输出是:

four needle
five

如您所见,这种幼稚的解决方案不起作用:

$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five

Answers:



8

您似乎正在使用GNU 。使用GNU grep,您可以传递--perl-regex标志以激活PCRE,然后提供否定的超前断言,例如下面的示例

grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five

这里值得注意的主要的事情是,(?:(?!STRING).)*STRING因为[^CHAR]*CHAR


@ 1_CR ...先生..这太棒了..:P露出笑容了ack
Rahul Patil

@RahulPatil。:-),是的,GNU grep很好。
iruvar

那不是我想要的。无论“忽略我”是在“针头”之前还是之后,我都希望它起作用。
Flimm 2013年

@RahulPatil,谢谢,我已将其修复为最新版本
iruvar

很有用。尤其是在具有上下文的grep情况下,您希望排除紧密匹配的行,但没有模式的特定部分。接近原始问题,但不完全相同。
gaoithe '16

2

我建议改用awk,因为它可以更好地处理多行IO。要么1)管的结果,GNU AWK与--\n如记录分隔符,或2)是否所有的匹配中AWK。

选项1

<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'

输出:

four needle                                                                                  
five
--

注意,此选项在整个记录中搜索ignore me,设置FS=1和匹配$1以仅与第一行进行比较。

选项2

<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1

有多个ignore me文件,然后,AWK不能作品
拉胡尔·帕蒂尔

@RahulPatil:您能否重新表达或添加更多细节到您的问题?我不明白你在问什么。
2013年

@Thos使用此输入文件测试您的示例paste.ubuntu.com/6252860
Rahul Patil

@RahulPatil:我明白您的意思了,选项1假定--\n每个匹配组之间都有一个分隔符,如果组彼此相邻,则不存在分隔符。如何处理相邻的组是特定于任务的,因此这不一定是错误的。选项2不取决于分隔符,也不受影响。
2013年
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.