2016-06-07 23 views
5

Đôi khi tôi là grep -ing hàng ngàn tệp và sẽ rất tuyệt khi thấy một số loại tiến trình (thanh hoặc trạng thái).grep - cách xuất thanh tiến trình hoặc trạng thái

Tôi biết điều này là không nhỏ vì grep kết quả đầu ra các kết quả tìm kiếm để STDOUT và quy trình làm việc mặc định của tôi là tôi xuất kết quả vào một tập tin và muốn tiến độ thanh/trạng thái để có đầu ra để STDOUT hoặc STDERR.

Điều này có yêu cầu sửa đổi mã nguồn của grep không?

lệnh lý tưởng là:

grep -e "STRING" --results="FILE.txt"

và tiến độ:

[curr file being searched], number x/total number of files 

ghi vào STDOUT hoặc STDERR

+0

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 –

Trả lời

7

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.)

+0

Câu trả lời rất tốt và gần như hoàn chỉnh. Hãy đăng một ví dụ về cách sử dụng các lệnh 'find, parallel, grep' để hoàn thành nhiệm vụ và tôi sẽ đánh dấu nó là được chấp nhận. – Adrian

+0

@adrian: nó sẽ giúp biết làm thế nào bạn hiện đang gọi grep: điều '-r' chỉ là một phỏng đoán. – rici

+0

lệnh grep thông thường của tôi là 'grep -e" STRING "* -r'. Thực hiện một lô * X tệp mỗi lần là một ý tưởng hoàn hảo. – Adrian

0

Tôi khá chắc chắn rằng bạn sẽ cần phải thay đổi mã nguồn grep. Và những thay đổi đó sẽ rất lớn.

Hiện tại grep không biết có bao nhiêu dòng tệp cho đến khi nó phân tích cú pháp toàn bộ tệp. Đối với yêu cầu của bạn, nó sẽ cần phải phân tích cú pháp tệp 2 lần hoặc ít nhất là xác định toàn bộ dòng bất kỳ cách nào khác.

Lần đầu tiên nó sẽ xác định số dòng cho thanh tiến trình. Lần thứ hai nó thực sự sẽ thực hiện công việc tìm kiếm mẫu của bạn.

Điều này sẽ không chỉ tăng thời gian chạy mà còn vi phạm một trong những triết lý UNIX chính.

  1. Làm cho mỗi chương trình hoạt động tốt. Để làm một công việc mới, xây dựng lại hơn là làm phức tạp các chương trình cũ bằng cách thêm "tính năng" mới. (source)

Có thể có các công cụ khác ngoài kia cho nhu cầu của bạn, nhưng afaik grep sẽ không phù hợp ở đây.

+1

OP không nói gì về số lượng dòng, chỉ các tệp.Và nó thậm chí không rõ ràng rằng số lượng dòng sẽ hữu ích; một số liệu thống kê đơn giản hơn để thu thập sẽ là tổng số byte (mà bạn có thể nhận được từ cuộc gọi đến stat), và đó cũng là một thống kê chính xác hơn, vì grep thực sự đọc trong các khối, chứ không phải các dòng. Tuy nhiên, tôi đồng ý với triết lý cơ bản về câu trả lời của bạn. – rici

+0

Xin lỗi tôi đã hiểu nhầm đầu ra 'số x' một ý nghĩ anh ta có nghĩa là dòng x trong tập tin y. – cb0

1

tôi normaly sử dụng một cái gì đó như thế này:

grep | tee "FILE.txt" | cat -n | sed 's/^/match: /;s/$/  /' | tr '\n' '\r' 1>&2 

Nó không phải là hoàn hảo, vì nó chỉ hiển thị các trận đấu, và nếu họ để dài hoặc khác nhau đến nhiều trong thời gian có những sai sót, nhưng nó phải cung cấp bạn với ý tưởng chung.

Hoặc đơn giản chấm:

grep | tee "FILE.txt" | sed 's/.*//' | tr '\n' '.' 1>&2 
+1

Điều này cho biết trạng thái như thế nào? – Adrian

+0

'grep -e" STRING "| tee "FILE.txt" 'hy vọng câu trả lời cho' grep -e "STRING" --results = "FILE.txt" ', nhưng không phải là trạng thái đầy đủ như' x/tổng số tệp' . Nó chỉ hiển thị số lượng các đối sánh đã được xử lý. –

1

Hãy thử chương trình song song

find * -name \*.[ch] | parallel -j5 --bar '(grep grep-string {})' > output-file 

Mặc dù tôi thấy điều này là chậm hơn so với một đơn giản

find * -name \*.[ch] | xargs grep grep-string > output-file 
Các vấn đề liên quan