này sẽ không nhất thiết đòi hỏi phải sửa đổi grep
, mặc dù bạn có thể có thể có được một thanh tiến trình chính xác hơn với một sửa đổi như vậy.
Nếu bạn đang tìm kiếm "hàng nghìn tệp" với một lệnh gọi grep, rất có thể bạn đang sử dụng tùy chọn -r
để đệ quy cấu trúc thư mục.Trong trường hợp đó, thậm chí không rõ ràng rằng grep
biết số lượng tệp sẽ kiểm tra, bởi vì tôi tin rằng nó bắt đầu kiểm tra tệp trước khi khám phá toàn bộ cấu trúc thư mục. Khám phá cấu trúc thư mục đầu tiên có lẽ sẽ làm tăng tổng thời gian quét (và, quả thật vậy, luôn luôn có một chi phí để tạo ra các báo cáo tiến độ, đó là lý do tại sao vài tiện ích Unix truyền thống thực hiện điều này.)
Trong mọi trường hợp, đơn giản nhưng hơi thanh tiến trình không chính xác có thể thu được bằng cách xây dựng danh sách đầy đủ các tệp được quét và sau đó cho chúng vào grep
theo lô có kích thước, có thể là 100 hoặc có thể dựa trên tổng kích thước của lô. Các lô nhỏ sẽ cho phép các báo cáo tiến độ chính xác hơn nhưng chúng cũng sẽ tăng chi phí vì chúng yêu cầu khởi động quá trình grep bổ sung và thời gian khởi động quá trình có thể nhiều hơn là grepping một tệp nhỏ. Báo cáo tiến trình sẽ được cập nhật cho từng lô tệp, do đó bạn sẽ muốn chọn kích thước lô cho phép bạn cập nhật thường xuyên mà không tăng quá nhiều chi phí. Dựa vào kích thước lô trên tổng kích thước của tệp (sử dụng, ví dụ: stat
để tải tệp) sẽ làm cho báo cáo tiến độ chính xác hơn nhưng thêm chi phí bổ sung để xử lý khởi động.
Một lợi thế của chiến lược này là bạn cũng có thể chạy hai hoặc nhiều greps song song, điều này có thể làm tăng tốc quá trình một chút.
Nói chung, một tập lệnh đơn giản (chỉ chia các tệp theo số lượng, không theo kích thước và không cố gắng song song).
# Requires bash 4 and Gnu grep
shopt -s globstar
files=(**)
total=${#files[@]}
for ((i=0; i<total; i+=100)); do
echo $i/$total >>/dev/stderr
grep -d skip -e "$pattern" "${files[@]:i:100}" >>results.txt
done
Để đơn giản, tôi sử dụng globstar (**
) để đặt an toàn tất cả các tệp trong một mảng. Nếu phiên bản bash của bạn quá cũ, bạn có thể làm điều đó bằng cách lặp lại đầu ra của find
, nhưng điều đó không hiệu quả nếu bạn có nhiều tệp. Thật không may, không có cách nào mà tôi biết để viết một biểu thức globstar mà chỉ phù hợp với các tập tin. (**/
chỉ phù hợp với thư mục.) May mắn thay, GNU grep cung cấp tùy chọn -d skip
tự động bỏ qua thư mục. Điều đó có nghĩa rằng số lượng tập tin sẽ hơi không chính xác, vì các thư mục sẽ được tính, nhưng nó có thể không tạo ra nhiều khác biệt.
Có thể bạn sẽ muốn làm cho báo cáo tiến trình sạch hơn bằng cách sử dụng một số mã bảng điều khiển. Ở trên chỉ là để giúp bạn bắt đầu. Cách đơn giản nhất để chia thành các quy trình khác nhau là chia danh sách thành các phân đoạn khác nhau và chạy X khác nhau cho các vòng, mỗi lần có một điểm bắt đầu khác nhau. Tuy nhiên, có lẽ họ sẽ không kết thúc cùng một lúc để không phụ thuộc. Một giải pháp tốt hơn là GNU song song. Bạn có thể làm điều gì đó như thế này:
find . -type f -print0 |
parallel --progress -L 100 -m -j 4 grep -e "$pattern" > results.txt
(Đây -L 100
xác định rằng lên đến 100 tập tin này nên được trao cho mỗi trường hợp grep, và -j 4
xác định bốn quá trình song song tôi chỉ cần kéo những con số ra khỏi không khí, bạn'. có lẽ sẽ muốn điều chỉnh chúng.)
Bạn đã cân nhắc sử dụng tập lệnh để thực hiện? Nó đơn giản hơn việc chỉnh sửa mã nguồn grep –