Grep trong vài nghìn tập tin


13

Tôi có thư mục với 26 000 tệp cca và tôi cần grep trong tất cả các tệp này. Vấn đề là, tôi cần nó càng nhanh càng tốt, vì vậy không lý tưởng để tạo tập lệnh trong đó grep sẽ lấy tên của một tệp từ lệnh find và ghi khớp vào tệp. Trước khi phát hành "danh sách đối số quá dài", phải mất 2 phút để grep trong tất cả các tệp này. Có ý tưởng nào để làm nó không không? chỉnh sửa: có một tập lệnh tạo các tệp mới mọi lúc, vì vậy không thể đặt tất cả các tệp vào các thư mục khác nhau.


1
sử dụng findvới xargshoặcgrep -R
Eddy_Em

Nó hoạt động tốt, nhưng phải mất 10 phút ...
user2778979

Câu trả lời:


19

Với find:

cd /the/dir
find . -type f -exec grep pattern {} +

( -type flà chỉ tìm kiếm trong các tệp thông thường (cũng không bao gồm các liên kết tượng trưng ngay cả khi chúng trỏ đến các tệp thông thường). Nếu bạn muốn tìm kiếm trong bất kỳ loại tệp nào ngoại trừ các thư mục (nhưng hãy cẩn thận có một số loại tệp như fifos hoặc / dev / zero bạn thường không muốn đọc), thay thế -type fbằng GNU cụ thể ! -xtype d( -xtype dkhớp với các tệp của thư mục loại sau khi phân giải symlink)).

Với GNU grep:

grep -r pattern /the/dir

(nhưng hãy cẩn thận, trừ khi bạn có phiên bản GNU grep gần đây, nó sẽ theo các liên kết tượng trưng khi đi xuống thư mục). Các tệp không thường xuyên sẽ không được tìm kiếm trừ khi bạn thêm -D readtùy chọn. Các phiên bản gần đây của GNU grepvẫn sẽ không tìm kiếm bên trong symlink.

Các phiên bản GNU rất cũ findkhông hỗ trợ {} +cú pháp tiêu chuẩn , nhưng ở đó bạn có thể sử dụng phi tiêu chuẩn:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern

Biểu diễn có khả năng bị ràng buộc I / O. Đó là thời gian để thực hiện tìm kiếm sẽ là thời gian cần thiết để đọc tất cả dữ liệu đó từ bộ lưu trữ.

Nếu dữ liệu nằm trên một mảng đĩa dự phòng, việc đọc một số tệp tại một thời điểm có thể cải thiện hiệu suất (và có thể làm giảm chúng theo cách khác). Nếu các màn trình diễn không bị ràng buộc I / O (vì ví dụ, tất cả dữ liệu nằm trong bộ đệm) và bạn có nhiều CPU, đồng thời cũng grepscó thể giúp ích. Bạn có thể làm điều đó với tùy chọn xargscủa GNU -P.

Chẳng hạn, nếu dữ liệu nằm trên mảng RAID1 có 3 ổ đĩa hoặc nếu dữ liệu nằm trong bộ đệm và bạn có 3 CPU có thời gian dự phòng:

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern

(ở đây sử dụng -n1000để sinh ra một grep1000 tệp mới, tối đa 3 tệp chạy song song cùng một lúc).

Tuy nhiên, lưu ý rằng nếu đầu ra của grepđược chuyển hướng, bạn sẽ kết thúc với đầu ra xen kẽ xấu từ 3 grepquy trình, trong trường hợp đó bạn có thể muốn chạy nó dưới dạng:

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern

(trên hệ thống GNU hoặc FreeBSD gần đây) hoặc sử dụng --line-bufferedtùy chọn GNU grep.

Nếu patternlà một chuỗi cố định, việc thêm -Ftùy chọn có thể cải thiện vấn đề.

Nếu đó không phải là dữ liệu ký tự nhiều byte hoặc nếu phù hợp với mẫu đó, thì dữ liệu đó có phải là ký tự nhiều byte hay không, sau đó:

cd /the/dir &&
  LC_ALL=C grep -r pattern .

có thể cải thiện hiệu suất đáng kể.

Nếu bạn thường xuyên thực hiện các tìm kiếm như vậy, thì bạn có thể muốn lập chỉ mục dữ liệu của mình bằng một trong nhiều công cụ tìm kiếm ngoài kia.


3

26000 tệp trong một thư mục là rất nhiều cho hầu hết các hệ thống tệp. Có vẻ như một phần đáng kể thời gian đã được đọc thư mục lớn này. Hãy xem xét việc chia nó thành các thư mục nhỏ hơn chỉ với vài trăm tệp.

Gọi findkhông thể giải thích hiệu suất kém trừ khi bạn làm sai. Đó là một cách nhanh chóng để duyệt qua một thư mục và đảm bảo rằng bạn không có nguy cơ cố gắng thực thi một dòng lệnh quá dài. Đảm bảo rằng bạn sử dụng -exec grep PATTERN {} +, gói nhiều tệp nhất có thể cho mỗi lần gọi lệnh, và không -exec grep PATTERN {} \;thực thi grepmột lần cho mỗi tệp: thực thi lệnh một lần cho mỗi tệp có thể chậm hơn đáng kể.


Cảm ơn, tôi sẽ google một cái gì đó về nó và có lẽ tôi sẽ chia nó. Tôi đã thực hiện chính xác những gì bạn đang viết và mất nhiều thời gian hơn 3 lần so với chỉ ...
user2778979

Gilles, bạn đang nói rằng hiệu suất sẽ khác nhau đáng kể đối với 26.000 tệp trong một thư mục so với 26.000 tệp được phân phối trên 100 thư mục?
user001

1
@ user001 Có. Chúng khác nhau bao nhiêu tùy thuộc vào hệ thống tệp và có thể vào bộ lưu trữ bên dưới, nhưng tôi hy vọng bất kỳ hệ thống tệp nào sẽ nhanh hơn với 260 tệp trong mỗi 100 thư mục so với 26000 tệp trong một thư mục.
Gilles 'SO- ngừng trở nên xấu xa'

Cảm ơn bạn đã làm rõ. Tôi đã hỏi một câu hỏi tiếp theo về điểm này để hiểu cơ sở cho sự khác biệt.
user001

0

Nếu bạn cần grep TẤT CẢ các tệp nhiều lần (như bạn đã nói, đang chạy tập lệnh) Tôi sẽ khuyên bạn nên xem xét các đĩa ram, sao chép tất cả các tệp ở đó và sau đó grep các tệp nhiều lần, điều này sẽ tăng tốc tìm kiếm của bạn theo hệ số ít nhất 100 lần.

Bạn chỉ cần đủ ram. Khác, bạn nên xem xét lập chỉ mục các tập tin, ví dụ. vào lucene hoặc cơ sở dữ liệu nosql và sau đó chạy các truy vấn theo đó.


Như đã lưu ý ở nơi khác, điều này không giúp ích gì cho thực tế là có quá nhiều tệp để chạy grep. Cũng có một điểm: "có một tập lệnh tạo các tệp mới mọi lúc, vì vậy không thể đặt tất cả các tệp vào các thư mục khác nhau."
Jeff Schaller

-2

Tất cả các tập tin trong thư mục

grep 'search string' *

với đệ quy

grep -R 'search string' *

Muốn xây dựng -1?
Markus

4
Tôi đã không downvote, nhưng có một vài vấn đề với bạn: OP đã đề cập đến một "danh sách arg quá dài", cái đầu tiên của bạn sẽ không sửa và có lẽ là những gì OP đã làm trước đây. Điều thứ hai không giúp được gì trong vấn đề đó (sẽ giúp bạn sử dụng .thay vì *). *sẽ loại trừ các tệp chấm (mặc dù với -R, không phải các tệp trong thư mục đệ quy). -R trái ngược với -r theo các liên kết tượng trưng ngay cả với các phiên bản gần đây của GNU grep. Bạn cũng sẽ gặp vấn đề với các tệp trong thư mục hiện tại có tên bắt đầu bằng-
Stéphane Chazelas
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.