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 grep
s 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 find
thà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 b
trong một thư mục được gọi a<NL>.
hay nếu đó là hai tệp a
và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, find
sẽ 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, xargs
xem nó như là một đối số. Và trong trường hợp thứ hai (hai tệp):
.//a
.//b
Mà awk
sẽ để lại như vậy, vì vậy xargs
nhìn thấy hai đối số.