Câu trả lời:
grep -l string2 `grep -l string1 /path/*`
giống như
grep -l string2 $(grep -l string1 /path/*)
Chỉnh sửa: đây là lý do tại sao grep string1 /path/* | grep string2tôi không làm những gì tôi nghĩ alwbtc muốn.
$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$
Không tìm thấy gì, nhưng tệp b chứa cả hai chuỗi.
Đây là những gì tôi nghĩ alwbtc muốn
$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b
-ltùy chọn cho cả hai lệnh được coi là bằng nhau.
Ống này grepsang ống khác:
grep "string1" /path/to/files/* | grep "string2"
Đây là lệnh ack tương đương với câu trả lời của RedGrittyBrick :
ack string2 $(ack string1 -l)
Hoạt động theo cùng một cách (ngoại trừ acktheo mặc định tìm kiếm thư mục hiện tại theo cách đệ quy). Nội dung trong các $()tìm kiếm string1nhưng -lchỉ xuất ra tên tệp nơi tìm thấy chuỗi đó. Sau đó chúng được truyền dưới dạng đối số vào lệnh bên ngoài, có nghĩa string2là chỉ được tìm kiếm trong danh sách các tệp đó.
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)
hoặc ít dư thừa:
search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)
Điều này sẽ hoạt động nếu các chuỗi nằm trên các dòng khác nhau của cùng một tệp và cũng sẽ tránh các kết quả dương tính giả nếu tên tệp chứa một trong các chuỗi.
Để giải thích về giải pháp của @ RedGrittyBrick, một thiếu sót khi chạy lệnh không giám sát cộng với để chặn đầu ra lỗi như dự định và để tìm các tệp đệ quy bạn có thể xem xét
grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)
-stùy chọn sẽ chặn thông báo lỗi
-rtùy chọn cho phép tìm kiếm các chuỗi trong các thư mục được lồng tùy ý
!kết hợp với && echo /dev/nullđảm bảo rằng lệnh sẽ không bị treo. Mặt khác, nếu inner grepkhông tìm thấy bất kỳ tệp nào, nó sẽ không xuất ra bất cứ thứ gì do đó outer grepsẽ chờ vô thời hạn đầu vào để tìm kiếm. Giải pháp này xuất ra /dev/nulltrong những trường hợp này vì vậy outer grepsẽ tìm kiếm STRING1ở /dev/nullnơi mà nó được cho là không tìm thấy gì.
Tôi đang tìm kiếm một cách mở rộng để làm 2 hoặc nhiều chuỗi và đến với điều này:
grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3
Grep đầu tiên tìm đệ quy tên của các tệp chứa string1bên trong path-to-files.
Các kết quả được dẫn vào xargsđể chạy một hoặc nhiều lệnh grep trên các tệp đó string2.
Các kết quả sau đó được chuyển sang một xargslệnh khác cho string3- nó giống như xargscuộc gọi đầu tiên , nhưng tìm kiếm một chuỗi khác.
Việc sử dụng xargssẽ tránh được các vấn đề khi có quá nhiều kết quả mà dòng lệnh kết quả từ việc sử dụng back-tick quá dài.
Để tránh các cảnh báo, chúng tôi có thể chuyển hướng stderrđến /dev/null:
grep -rl string1 path-to-files 2>/dev/null | xargs grep -l string2
Không cần thiết cho các cuộc gọi grep tiếp theo vì string1đã được tìm thấy bên trong tệp nên các quyền được biết là tốt.
-ltùy chọn để trả về tên tệp thay vì các dòng. Sau đó, anh ta sử dụng ký hiệu đô la hoặc dấu ngoặc kép để chuyển danh sách đó làmFILEđối số vào grep thứ hai. Điều này cho phép grep thứ hai tìm kiếm toàn bộ từng tệp được tìm thấy thay vì các dòng riêng lẻ như trong giải pháp của tôi.