假设我想在整个树中搜索出现“Foo”的所有 CPP 文件。我可能会这样做:
find . -name "*.cpp" | xargs grep "Foo"
Run Code Online (Sandbox Code Playgroud)
现在假设我想列出只有那些情况下,其他一些字符串,说“酒吧”并没有在3线前一个结果的发生。
所以给定两个文件:
1 Foo
2 qwerty
3 qwerty
Run Code Online (Sandbox Code Playgroud)
1 Foo
2 Bar
3 qwerty
Run Code Online (Sandbox Code Playgroud)
我想构建一个简单的搜索,其中找到 a.cpp 中的“Foo”,但没有找到 b.cpp 中的“Foo”。
有没有办法以相当简单的方式实现这一目标?
Sté*_*las 17
与pcregrep
:
pcregrep --include='\.cpp$' -rnM 'Foo(?!(?:.*\n){0,2}.*Bar)' .
Run Code Online (Sandbox Code Playgroud)
关键在于该-M
选项是唯一的,pcregrep
用于匹配多行(pcregrep
在执行 RE 需要时,根据需要从输入文件中提取更多数据)。
(?!...)
是 perl/PCRE 否定前瞻 RE 运算符。Foo(?!...)
匹配Foo
,只要...
不匹配以下内容。
...
是(?:.*\n){0,2}.*Bar
(.
不匹配换行符),即 0 到 2 行后跟包含Bar
.
没关系,只需pcregrep
按照@StephaneChazelas 的建议使用即可。
这应该有效:
$ find . -name "*.cpp" |
while IFS= read -r file; do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Run Code Online (Sandbox Code Playgroud)
这个想法是使用 grep 的-A
开关来输出匹配的行和接下来的 N 行。然后通过 a 传递结果grep Bar
,如果不匹配(退出 > 0),则回显文件名。
如果您知道文件名合理(没有空格、换行符或其他奇怪的字符),您可以简化为:
$ for file in $(find . -name "*.cpp"); do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Run Code Online (Sandbox Code Playgroud)
例如:
terdon@oregano foo $ cat a.cpp
1 Foo
2 qwerty
3 qwerty
terdon@oregano foo $ cat b.cpp
1 Foo
2 Bar
3 qwerty
terdon@oregano foo $ cat c.cpp
1 Foo
2 qwerty
3 qwerty
4 qwerty
5. Bar
terdon@oregano foo $ for file in $(find . -name "*.cpp"); do grep -A 3 Foo "$file" | grep -q Bar || echo "$file"; done
./c.cpp
./a.cpp
Run Code Online (Sandbox Code Playgroud)
请注意,c.cpp
尽管包含,但仍会返回,Bar
因为 withBar
在 之后超过 3 行Foo
。您可以通过更改传递给的值来控制要搜索的行数-A
:
$ for file in $(find . -name "*.cpp"); do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
./a.cpp
Run Code Online (Sandbox Code Playgroud)
这是一个较短的(假设您使用bash
):
$ shopt -s globstar
$ for file in **/*cpp; do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
Run Code Online (Sandbox Code Playgroud)
正如 Stephane Chazelas 在评论中指出的那样,上述解决方案还将打印根本不包含的文件Foo
。这避免了:
for file in **/*cpp; do
grep -qm 1 Foo "$file" &&
(grep -A 3 Foo "$file" | grep -q Bar || echo "$file");
done
Run Code Online (Sandbox Code Playgroud)