Sudahlah, gunakan saja pcregrep
seperti yang disarankan oleh @StephaneChazelas.
Ini seharusnya bekerja:
$ find . -name "*.cpp" |
while IFS= read -r file; do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Idenya adalah menggunakan -A
saklar grep untuk menampilkan garis yang cocok dan garis N berikut. Anda kemudian meneruskan hasilnya melalui a grep Bar
dan jika itu tidak cocok (keluar> 0), maka Anda mengulangi nama file.
Jika Anda tahu Anda memiliki nama file yang waras (tanpa spasi, baris baru atau karakter aneh lainnya), Anda dapat menyederhanakan untuk:
$ for file in $(find . -name "*.cpp"); do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Sebagai contoh:
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
Perhatikan bahwa c.cpp
dikembalikan meskipun mengandung Bar
karena garis dengan Bar
lebih dari 3 baris setelah Foo
. Anda dapat mengontrol jumlah baris yang ingin Anda cari dengan mengubah nilai yang diteruskan ke -A
:
$ for file in $(find . -name "*.cpp"); do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
./a.cpp
Ini yang lebih pendek (dengan asumsi Anda menggunakan bash
):
$ shopt -s globstar
$ for file in **/*cpp; do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
PENTING
Seperti yang ditunjukkan Stephane Chazelas dalam komentar, solusi di atas juga akan mencetak file yang tidak mengandung Foo
sama sekali. Yang ini menghindari itu:
for file in **/*cpp; do
grep -qm 1 Foo "$file" &&
(grep -A 3 Foo "$file" | grep -q Bar || echo "$file");
done