決して心は、単に使用pcregrep
として提案 @StephaneChazelasで。
これはうまくいくはずです:
$ find . -name "*.cpp" |
while IFS= read -r file; do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
アイデアは、grepの-A
スイッチを使用して、一致した行とそれに続くN行を出力することです。次に、a grep Bar
を介して結果を渡し、それが一致しない場合(exit> 0)、ファイルの名前をエコーします。
正しいファイル名がある(スペース、改行、その他の奇妙な文字がない)ことがわかっている場合は、次のように簡略化できます。
$ for file in $(find . -name "*.cpp"); do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
例えば:
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
c.cpp
を含む行がから3行を超えBar
てBar
いるため、が含まれているにもかかわらずが返されることに注意してくださいFoo
。に渡される値を変更して、検索する行数を制御します-A
。
$ for file in $(find . -name "*.cpp"); do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
./a.cpp
これは短いものです(使用する場合bash
):
$ shopt -s globstar
$ for file in **/*cpp; do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
重要
Stephane Chazelasがコメントで指摘したように、上記のソリューションはまったく含まFoo
れていないファイルも印刷します。これはそれを回避します:
for file in **/*cpp; do
grep -qm 1 Foo "$file" &&
(grep -A 3 Foo "$file" | grep -q Bar || echo "$file");
done