Grep dalam beberapa ribu file

13

Saya memiliki direktori dengan cca 26 000 file dan saya perlu membaca semua file ini. Masalahnya adalah, saya membutuhkannya secepat mungkin, jadi tidak ideal untuk membuat skrip di mana grep akan mengambil nama satu file dari perintah find dan menulis kecocokan ke file. Sebelum masalah "daftar argumen terlalu panjang" butuh waktu 2 menit untuk memahami semua file ini. Ada ide bagaimana melakukannya? sunting: ada skrip yang membuat file baru setiap saat, jadi tidak mungkin untuk meletakkan semua file ke direktori yang berbeda.

pengguna2778979
sumber
1
gunakan finddengan xargsataugrep -R
Eddy_Em
Ini bekerja dengan baik, tetapi butuh 10 menit ...
user2778979

Jawaban:

19

Dengan find:

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

( -type fadalah hanya mencari di file biasa (juga mengecualikan symlink bahkan jika mereka menunjuk ke file biasa). Jika Anda ingin mencari di semua jenis file kecuali direktori (tapi waspadalah ada beberapa jenis file seperti fifos atau / dev / zero yang Anda umumnya tidak ingin membaca), ganti -type fdengan GNU-spesifik ! -xtype d( -xtype dcocok untuk file-file dari direktori tipe setelah resolusi symlink)).

Dengan GNU grep:

grep -r pattern /the/dir

(tetapi berhati-hatilah bahwa kecuali Anda memiliki versi terbaru GNU grep, itu akan mengikuti symlink ketika turun ke direktori). File tidak biasa tidak akan dicari kecuali Anda menambahkan -D readopsi. Versi terbaru dari GNU grepmasih tidak akan mencari di dalam symlink.

Versi GNU yang sangat lama findtidak mendukung {} +sintaks standar , tetapi di sana Anda dapat menggunakan non-standar:

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

Pertunjukan cenderung terikat I / O. Itu adalah waktu untuk melakukan pencarian akan menjadi waktu yang dibutuhkan untuk membaca semua data dari penyimpanan.

Jika data pada array disk yang redundan, membaca beberapa file sekaligus dapat meningkatkan kinerja (dan sebaliknya dapat menurunkannya). Jika kinerjanya tidak terikat I / O (karena misalnya semua data ada dalam cache), dan Anda memiliki banyak CPU, lakukan bersamaangreps dapat juga membantu. Anda dapat melakukannya dengan GNU xargs's -Ppilihan.

Misalnya, jika data pada array RAID1 dengan 3 drive, atau jika data dalam cache dan Anda memiliki 3 CPU yang waktunya luang:

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

(di sini menggunakan -n1000 untuk menelurkan yang baru grepsetiap 1000 file, hingga 3 berjalan secara paralel pada suatu waktu).

Namun perhatikan bahwa jika output grepdiarahkan, Anda akan berakhir dengan output yang disisipkan sangat buruk dari 3 grepproses, dalam hal ini Anda mungkin ingin menjalankannya sebagai:

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

(pada sistem GNU atau FreeBSD baru-baru ini) atau gunakan --line-bufferedopsi GNU grep.

Jika patternstring tetap, menambahkan -Fopsi dapat memperbaiki masalah.

Jika itu bukan data karakter multi-byte, atau jika untuk pencocokan pola itu, tidak masalah apakah data tersebut karakter multi-byte atau tidak, maka:

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

dapat meningkatkan kinerja secara signifikan.

Jika Anda akhirnya sering melakukan pencarian seperti itu, maka Anda mungkin ingin mengindeks data Anda menggunakan salah satu dari banyak mesin pencari di luar sana.

Stéphane Chazelas
sumber
3

26000 file dalam satu direktori banyak untuk sebagian besar sistem file. Kemungkinan sebagian besar waktu diambil untuk membaca direktori besar ini. Pertimbangkan membaginya menjadi direktori yang lebih kecil dengan masing-masing hanya beberapa ratus file.

Menelepon findtidak dapat menjelaskan kinerja yang buruk kecuali Anda salah melakukannya. Ini cara cepat melintasi direktori, dan memastikan bahwa Anda tidak mengambil risiko mencoba mengeksekusi baris perintah yang terlalu lama. Pastikan bahwa Anda menggunakan -exec grep PATTERN {} +, yang mengemas file sebanyak mungkin per permintaan doa, dan tidak -exec grep PATTERN {} \;, yang mengeksekusi grepsekali per file: mengeksekusi perintah sekali per file cenderung jauh lebih lambat.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih, saya akan google sesuatu tentang itu dan mungkin saya akan membaginya. Saya membuat persis apa yang Anda tulis dan butuh 3 kali lebih lama daripada hanya ...
user2778979
Gilles, apakah Anda mengatakan bahwa kinerja akan berbeda secara signifikan untuk 26.000 file dalam satu direktori versus 26.000 file yang didistribusikan melalui, katakanlah, 100 direktori?
user001
1
@ user001 Ya. Seberapa besar perbedaannya tergantung pada sistem file dan kemungkinan pada penyimpanan yang mendasarinya, tetapi saya berharap sistem file mana pun akan terukur lebih cepat dengan 260 file di masing-masing 100 direktori dibandingkan dengan 26.000 file dalam satu direktori.
Gilles 'SO- berhenti bersikap jahat'
Terimakasih atas klarifikasinya. Saya mengajukan pertanyaan lanjutan tentang hal ini untuk memahami dasar perbedaan.
user001
0

Jika Anda perlu grep SEMUA file beberapa kali (seperti yang Anda katakan, menjalankan skrip) Saya sarankan melihat ke ram ram, salin semua file di sana dan kemudian grep file beberapa kali, ini akan mempercepat pencarian Anda dengan faktor setidaknya 100x.

Anda hanya perlu ram yang cukup. Lain, Anda harus melihat ke dalam mengindeks file, misalnya. ke dalam lucene atau basis data nosql dan kemudian menjalankan query atas itu.

Tobias Feldballe
sumber
Seperti dicatat di tempat lain, ini tidak membantu fakta bahwa ada terlalu banyak file untuk dijalankan grep. Ada juga intinya bahwa: "ada skrip yang membuat file baru setiap saat, jadi tidak mungkin untuk meletakkan semua file ke direktori yang berbeda."
Jeff Schaller
-2

Semua file dalam direktori

grep 'search string' *

dengan rekursif

grep -R 'search string' *
Markus
sumber
Ingin menguraikan -1?
Markus
4
Saya tidak mengundurkan diri, tetapi ada beberapa masalah dengan masalah Anda: OP menyebutkan "daftar arg terlalu panjang", yang tidak akan diperbaiki oleh orang pertama Anda dan mungkin apa yang dilakukan OP sebelumnya. Yang kedua tidak membantu baik dalam hal itu (akan membantu jika Anda menggunakan, .bukan *). *akan mengecualikan file dot (meskipun dengan -R, bukan yang ada di direktori berulang). -R sebagai lawan dari -r mengikuti symlink bahkan dengan versi terbaru dari GNU grep. Anda juga akan memiliki masalah dengan file di direktori saat ini yang namanya dimulai dengan-
Stéphane Chazelas