Tối ưu hóa GNU grep


8

Tôi đang sử dụng egrep ( grep -E) với tập tin THỰC HIỆN. ( -f path/to/file).

Điều này được thực hiện trong một vòng lặp vô hạn trên một luồng văn bản. Điều này ngụ ý rằng tôi không thể tích lũy và chuyển TẤT CẢ đầu vào cho grep cùng một lúc (như *.log).

Có cách nào để grep "lưu" NFA mà nó đang xây dựng từ tệp MẪU để sử dụng cho lần chạy tiếp theo không?

Tôi đã tìm kiếm Google và đọc tài liệu không có may mắn.

Tôi sẽ cố gắng giải thích thêm một chút nữa. Tôi cần xác định một số chuỗi cố định với biểu thức chính quy (Đây không phải là một phần của câu hỏi nhưng vui lòng đề xuất khác) như địa chỉ IP, tên miền, v.v. Việc tìm kiếm được thực hiện trên nguồn cấp dữ liệu từ internet. Bạn có thể nghĩ về nó như một dòng văn bản. Tôi không thể sử dụng greptrên tất cả các đầu vào vì đó là một luồng. Tôi có thể tích lũy một đoạn luồng và sử dụng greptrên luồng đó (do đó không sử dụng greptrên mỗi dòng) nhưng điều này cũng bị hạn chế (giả sử trong 30 giây).

Tôi biết grepđang xây dựng một NFA từ tất cả các mẫu của nó (trong trường hợp của tôi từ một tệp). Vì vậy, câu hỏi của tôi ở đây là: tôi có thể bảo greplưu NFA đó cho lần chạy tiếp theo không, vì nó sẽ không thay đổi? Điều đó sẽ giúp tôi tiết kiệm thời gian xây dựng NFA đó mỗi lần.


Ý của bạn là gì Điều này được thực hiện trong một vòng lặp vô hạn trên một luồng văn bản ? Bạn đang nói rằng bạn đang chạy một grepdòng trên mỗi dòng văn bản? Văn bản đến từ đâu? Sẽ tail -flà một lựa chọn?
Stéphane Chazelas

Giả sử tôi đang tích lũy luồng trong 30 giây và sau đó chạy greptrên đoạn đó.
bergerg

1
Vẫn chưa rõ lý do tại sao bạn cần chạy grepnhiều lần. Có thể liên quan: Tại sao việc kết hợp chuỗi 1250 với các mẫu 90k lại chậm như vậy?
Stéphane Chazelas

5
grepcó nghĩa là để làm việc trên một dòng văn bản, tôi vẫn không hiểu tại sao bạn cần chạy một số trường hợp. Tại sao bạn không thể cho tất cả những người đó vào cùng một grepví dụ? Tại sao bạn cần tích lũy chúng trước khi cho ăn grep?
Stéphane Chazelas

2
Hãy xem flex và viết chương trình của riêng bạn, điều đó có thể nhanh hơn nhiều.
dùng2064000

Câu trả lời:


14

Không, không có điều đó. Nói chung, chi phí bắt đầu grep(rẽ nhánh một quy trình mới, tải thư viện chia sẻ, thực thi, liên kết động ...) sẽ lớn hơn rất nhiều so với việc biên dịch các biểu thức chính, vì vậy loại tối ưu hóa này sẽ rất ít ý nghĩa.

Mặc dù hãy xem Tại sao việc kết hợp chuỗi 1250 với các mẫu 90k lại chậm như vậy? về một lỗi trong một số phiên bản GNU grepsẽ khiến nó đặc biệt chậm đối với một số lượng lớn các biểu thức chính quy.

Có thể ở đây, bạn có thể tránh chạy grepnhiều lần bằng cách cho các khối của mình vào cùng một grepví dụ, bằng cách sử dụng nó như một đồng xử lý và sử dụng một điểm đánh dấu để phát hiện kết thúc. Với zshvà GNU grepawktriển khai khác hơn mawk:

coproc grep -E -f patterns -e '^@@MARKER@@$' --line-buffered
process_chunk() {
  { cat; echo @@MARKER@@; } >&p & awk '$0 == "@@MARKER@@"{exit};1' <&p
}
process_chunk < chunk1 > chunk1.grepped
process_chunk < chunk2 > chunk2.grepped

Mặc dù nó có thể đơn giản hơn để làm toàn bộ với awkhoặc perlthay vào đó.

Nhưng nếu bạn không cần grepđầu ra để đi vào các tệp khác nhau cho các khối khác nhau, bạn luôn có thể thực hiện:

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output

Tôi có veraion 3+ của grep vì vậy đó không phải là vấn đề. Thậm chí không xem xét các chi phí rèn. Tôi đoán tôi sẽ cố gắng phát trực tiếp mọi thứ grep. Cảm ơn.
bergerg

Không thể thực thi và các thư viện chia sẻ sẽ ở trong bộ đệm RAM sau khi kết thúc quá trình (trừ khi OP thực sự thiếu RAM)?
Dmitry Grigoryev

2
@DmitryGrigoryev, vâng, rất có thể, vẫn cần được ánh xạ trong không gian địa chỉ quy trình và thực hiện chỉnh sửa liên kết. Có nhiều thứ giống như tải và phân tích dữ liệu miền địa phương, phân tích các tùy chọn, môi trường ... Vấn đề là chi phí của regcomp () bị pha loãng trong tất cả chi phí đó. Điều đầu tiên cần làm khi tối ưu hóa là tránh chạy vài greps ở nơi đầu tiên.
Stéphane Chazelas

1

Tôi không thể sử dụng grep trên tất cả các đầu vào vì đó là một luồng. Tôi có thể tích lũy một đoạn stream và sử dụng grep trên nó ...

Bạn có biết rằng đường ống chặn? Nếu bạn đặt một cái gì đó cho grep và tất cả đầu vào không có sẵn, grep sẽ đợi cho đến khi nó có sẵn và sau đó tiếp tục như thể đầu vào có ở đó cùng.

$ ( echo a1; echo b1; sleep 5; echo a2 ) | grep 'a.'
a1
a2

EDIT: Làm thế nào các đường ống hoạt động, ví dụ như cmd1 | cmd2là cả hai chương trình sẽ bắt đầu cùng một lúc, với một "bộ đệm chunk" 65,536 byte giữa chúng. Khi cmd2cố gắng đọc và bộ đệm đó trống, nó sẽ đợi một đoạn có sẵn. Khi cmd1cố gắng viết và bộ đệm đó đã đầy, nó sẽ đợi cho đến khi cmd2đọc nó.

Từ những gì tôi có thể đọc, không cần phải cắt đầu vào thành các đoạn và chuyển chúng sang grep riêng. Điều đó đã được thực hiện tự động.

EDIT2: grepcũng nên in kết quả ngay khi tìm thấy chúng trong luồng. Không cần cho luồng kết thúc trước khi bạn có thể nhận được kết quả của mình.


0

Có lẽ bạn có thể "sử dụng grep trên tất cả các đầu vào"? Sử dụng nc(netcat), hoặc thông qua script, hoặc thông qua các công cụ tương tự khác? Đặc biệt là nếu tệp mẫu của bạn có kích thước có thể quản lý được (giả sử dưới 1000 regexps).

Ví dụ đầu tiên : Bạn có thể egrepmột số kết nối phát trực tuyến: (ở đây mẫu được hiển thị với nc, nhưng những người khác có thể áp dụng)

prompt:/some/path $ nc somehost someport | egrep -f patternfile | gzip -c - > results.gz

# and while this is running, you can have a look at the growing results.gz:
prompt:/some/otherpath $ tail -f /some/path/results.gz | gzip -c - | less

(lưu ý: bạn thậm chí có thể: touch /some/path/results.gztrước khi bắt đầu nclệnh và có tail -ftệp (trống) đó để không bỏ lỡ bất cứ điều gì. Dù sao, results.gz sẽ chứa mọi thứ bạn muốn bắt)

ví dụ thứ hai : Bạn thậm chí có thể egreptrên phiên shell hiện đang chạy (và hiển thị một cách khác để theo dõi tiến trình):

#in 1 terminal:
prompt:/home/userA $ script
Script command is started. The file is typescript.
prompt:/home/userA $ 
 ... doing here whatever you want (start IRC? etc) ...
prompt:/home/userA $ ctrl-d # to end the current script session
Script command is complete. The file is typescript.

#and in another terminal, while you are "doing here whatever you want" :
prompt:/home/somewhere $ tail -f /home/userA/typescript | egrep -f patternfile  | tee /some/place/to/store/results.gz

egreplà một phiên bản hiệu quả cao của grep, trên hầu hết các hệ thống (xem một số infos xen kẽ trên: https://swtch.com/~rsc/regapi/regapid1.html )


bạn thậm chí có thể sử dụng exemple1 cho những thứ như đầu ra dd, v.v.
Olivier Dulac

Lưu ý bên lề: grep hiệu quả hơn phần lớn hơn của regex là (ví dụ: tìm chuỗi hoặc regrec slà nhiều, chậm hơn so với khớp somethingvà điều này chậm hơn so với khớp something even much longer(phần sau cho phép khớp regrec bỏ qua lớn hơn Các phần của đầu vào khi khác nhau) Trên các tệp lớn, về cơ bản, nó "chia" thời gian để phân tích nó theo tỷ lệ độ dài (nghĩa là, lấy 1 ký tự đã biết chậm hơn gần 40 lần so với khớp chuỗi 40 ký tự đã biết. Tôi đã không ' t prof nó nhưng nó thực sự đáng chú ý.)
Olivier Dulac
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.