假设我想在整个树中搜索出现“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)