使用grep
,我想选择与某个模式匹配但与另一个模式不匹配的所有行。我希望能够使用单个调用,grep
以便我可以使用--after-context
选项(或--before-context
、 或--context
)。
-v
在这里不可行,因为它否定了我grep
使用该-e
选项传递的所有模式。
我想寻找行匹配needle
,忽略行匹配ignore me
,有一行以下上下文。
这是我的输入文件:
one needle ignore me
two
three
four needle
five
Run Code Online (Sandbox Code Playgroud)
我想要的输出是:
four needle
five
Run Code Online (Sandbox Code Playgroud)
如您所见,这个幼稚的解决方案不起作用:
$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 10
如果你有 GNU grep,你可以使用Perl 正则表达式,它有一个否定结构。
grep -A1 -P '^(?!.*ignore me).*needle'
Run Code Online (Sandbox Code Playgroud)
如果您没有 GNU grep,则可以在 awk 中模拟其前后上下文选项。
awk -v after=3 -v before=2 '
/needle/ && !/ignore me/ {
for (i in h) {
print h[i];
delete h[i];
}
until = NR + after;
}
{
if (NR <= until) print $0; else h[NR] = $0;
delete h[NR-before];
}
END {exit !until}
'
Run Code Online (Sandbox Code Playgroud)
您似乎正在使用 GNU grep。使用 GNU grep,您可以传入--perl-regex
标志以激活 PCRE,然后提供否定的前瞻断言,示例如下
grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five
Run Code Online (Sandbox Code Playgroud)
这里值得注意的主要的事情是,(?:(?!STRING).)*
是STRING
因为[^CHAR]*
是CHAR