Với các công cụ GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Bạn có thể làm chuẩn:
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
Nhưng điều đó sẽ chạy hai greps mỗi tập tin. Để tránh chạy nhiều greps mà vẫn có thể di động trong khi vẫn cho phép bất kỳ ký tự nào trong tên tệp, bạn có thể làm:
convert_to_xargs() {
sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\\"
print ""
}
line = $0
}'
END { print line }'
}
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
Ý tưởng là chuyển đổi đầu ra findthành định dạng phù hợp với xargs (mong đợi một khoảng trống (SPC / TAB / NL và các khoảng trống khác từ ngôn ngữ của bạn với một số cách triển khai xargs) danh sách các từ có thể trích dẫn đơn, dấu ngoặc kép và dấu gạch chéo ngược thoát khoảng trống và nhau).
Nói chung, bạn không thể xử lý hậu kỳ của đầu ra find -print, bởi vì nó phân tách các tên tệp bằng một ký tự dòng mới và không thoát khỏi các ký tự dòng mới được tìm thấy trong tên tệp. Chẳng hạn, nếu chúng ta thấy:
./a
./b
Chúng tôi không có cách nào để biết liệu đó là một tệp được gọi btrong một thư mục được gọi a<NL>.hay nếu đó là hai tệp avàb .
Bằng cách sử dụng .//., vì //không thể xuất hiện theo cách khác trong đường dẫn tệp dưới dạng đầu ra find(vì không có thư mục nào có tên trống và /không được phép trong tên tệp), chúng tôi biết rằng nếu chúng tôi thấy một dòng có chứa //, thì đó là dòng đầu tiên của một tên tệp mới. Vì vậy, chúng ta có thể sử dụng nóawk lệnh để thoát tất cả các ký tự dòng mới nhưng những ký tự đi trước các dòng đó.
Nếu chúng ta lấy ví dụ ở trên, findsẽ xuất ra trong trường hợp đầu tiên (một tệp):
.//a
./b
Mà awk thoát đến:
.//a\
./b
Vì vậy, xargsxem nó như là một đối số. Và trong trường hợp thứ hai (hai tệp):
.//a
.//b
Mà awksẽ để lại như vậy, vì vậy xargsnhìn thấy hai đối số.