Đừng bận tâm, chỉ cần sử dụng pcregreptheo đề xuất của @StephaneChazelas.
Điều này sẽ làm việc:
$ find . -name "*.cpp" |
while IFS= read -r file; do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Ý tưởng là sử dụng -Acông tắc của grep để xuất các dòng khớp và N dòng sau. Sau đó, bạn chuyển kết quả qua a grep Barvà nếu điều đó không khớp (exit> 0), thì bạn lặp lại tên của tệp.
Nếu bạn biết bạn có tên tệp lành mạnh (không có dấu cách, dòng mới hoặc các ký tự lạ khác), bạn có thể đơn giản hóa thành:
$ for file in $(find . -name "*.cpp"); do
grep -A 3 Foo "$file" | grep -q Bar || echo "$file";
done
Ví dụ:
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
Lưu ý rằng c.cppđược trả về mặc dù có chứa Barbởi vì dòng với Barhơn 3 dòng sau Foo. Bạn cna kiểm soát số lượng dòng bạn muốn tìm kiếm bằng cách thay đổi giá trị được chuyển sang -A:
$ for file in $(find . -name "*.cpp"); do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
./a.cpp
Đây là một cái ngắn hơn (giả sử bạn sử dụng bash):
$ shopt -s globstar
$ for file in **/*cpp; do
grep -A 10 Foo "$file" | grep -q Bar || echo "$file";
done
QUAN TRỌNG
Như Stephane Chazelas đã chỉ ra trong các bình luận, các giải pháp trên cũng sẽ in các tệp không chứa Foogì cả. Điều này tránh rằng:
for file in **/*cpp; do
grep -qm 1 Foo "$file" &&
(grep -A 3 Foo "$file" | grep -q Bar || echo "$file");
done