Mengoptimalkan GNU grep

8

Saya menggunakan egrep ( grep -E) dengan file POLA. ( -f path/to/file).

Ini dilakukan dalam loop tak terbatas pada aliran teks. Ini menyiratkan bahwa saya tidak dapat mengakumulasi dan meneruskan SEMUA input untuk menerima sekaligus (seperti *.log).

Apakah ada cara untuk membuat grep "save" NFA yang sedang dibangun dari file POLA untuk digunakan untuk menjalankan selanjutnya?

Saya telah mencari Google dan membaca dokumentasi tanpa hasil.

Saya akan mencoba menjelaskannya sedikit lagi. Saya perlu mencari sejumlah string yang tetap dengan regex (Ini bukan bagian dari pertanyaan, tetapi jangan ragu untuk menyarankan sebaliknya) seperti alamat IP, domain, dll. Pencarian dilakukan berdasarkan umpan dari internet. Anda dapat menganggapnya sebagai aliran teks. Saya tidak dapat menggunakan grepsemua input karena ini adalah stream. Saya dapat mengakumulasi sepotong aliran dan menggunakannya grep(jadi tidak menggunakan greppada setiap baris) tetapi ini juga terbatas (katakanlah selama 30 detik).

Saya tahu grepsedang membangun NFA dari semua polanya (dalam kasus saya dari file). Jadi pertanyaan saya di sini adalah: dapatkah saya katakan grepuntuk menyimpan NFA untuk menjalankan selanjutnya, karena itu tidak akan berubah? Itu akan menyelamatkan saya waktu membangun NFA itu setiap waktu.

bergerg
sumber
Apa yang Anda maksudkan dengan ini dilakukan dalam loop tak terbatas pada aliran teks ? Apakah Anda mengatakan Anda menjalankan satu grepteks per baris? Dari mana teks itu berasal? Apakah tail -fakan menjadi pilihan?
Stéphane Chazelas
Katakanlah saya mengakumulasikan aliran selama 30 detik dan kemudian jalankan greppotongan itu.
bergerg
1
Masih belum jelas mengapa Anda harus menjalankan grepbeberapa kali. Kemungkinan terkait: Mengapa mencocokkan 1250 string dengan pola 90k sangat lambat?
Stéphane Chazelas
5
grepdimaksudkan untuk bekerja pada aliran teks, saya masih belum mengerti mengapa Anda perlu menjalankan beberapa instance. Mengapa Anda tidak bisa memberi makan semua orang ke grepcontoh yang sama ? Mengapa Anda harus menumpuknya sebelum disusui grep?
Stéphane Chazelas
2
Lihatlah fleksibel , dan menulis program Anda sendiri, yang mungkin ternyata jauh lebih cepat.
user2064000

Jawaban:

14

Tidak, tidak ada yang seperti itu. Umumnya biaya untuk memulai grep(melakukan proses baru, memuat library yang dapat dieksekusi, shared, linkage dinamis ...) akan jauh lebih besar daripada mengkompilasi regexps, jadi optimasi semacam ini tidak masuk akal.

Meskipun melihat Mengapa mencocokkan 1250 string dengan pola 90k sangat lambat? tentang bug di beberapa versi GNU grepyang akan membuatnya sangat lambat untuk sejumlah besar regexps.

Mungkin di sini, Anda dapat menghindari menjalankan grepbeberapa kali dengan memberi makan potongan Anda ke grepcontoh yang sama , misalnya dengan menggunakannya sebagai proses bersama dan menggunakan penanda untuk mendeteksi akhirnya. Dengan zshdan GNU grepdan awkimplementasi selain 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

Meskipun mungkin lebih mudah untuk melakukan semuanya dengan awkatau perlsebagai gantinya.

Tetapi jika Anda tidak membutuhkan grepoutput untuk masuk ke file yang berbeda untuk potongan yang berbeda, Anda selalu dapat melakukannya:

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output
Stéphane Chazelas
sumber
Saya memiliki veraion 3+ dari grep jadi bukan itu masalahnya. Bahkan tidak mempertimbangkan overhead forking. Saya kira saya akan mencoba untuk melakukan streaming apa grepadanya. Terima kasih.
bergerg
Tidakkah executable dan shared library tetap berada dalam buffer RAM setelah proses penghentian (kecuali OP sebenarnya rendah pada RAM)?
Dmitry Grigoryev
2
@DmitryGrigoryev, ya, kemungkinan besar, masih perlu dipetakan dalam ruang alamat proses dan melakukan pengeditan tautan. Ada lebih seperti memuat dan mem-parsing data lokal, parsing opsi, lingkungan ... Intinya adalah bahwa biaya regcomp () terdilusi dalam semua overhead itu. Hal pertama yang harus dilakukan ketika mengoptimalkan adalah menghindari menjalankan beberapa greps di tempat pertama.
Stéphane Chazelas
1

Saya tidak dapat menggunakan grep pada semua input karena ini adalah aliran. Saya dapat mengumpulkan sepotong aliran dan menggunakan grep di atasnya ...

Apakah Anda sadar bahwa saluran pipa itu memblokir? Jika Anda mengirim sesuatu ke grep dan semua input tidak tersedia, grep akan menunggu sampai tersedia dan kemudian melanjutkan seolah-olah input ada di sana selama ini.

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

EDIT: Bagaimana jaringan pipa bekerja, misalnya dengan cmd1 | cmd2adalah bahwa kedua program akan mulai pada saat yang sama, dengan misalnya 65,536-byte "chunk buffer" di antara mereka. Ketika cmd2mencoba membaca dan buffer itu kosong, buffer akan menunggu tersedia. Ketika cmd1mencoba menulis dan buffer itu penuh, ia akan menunggu sampai cmd2membacanya.

Dari apa yang bisa saya baca, tidak perlu memotong input menjadi potongan-potongan dan meneruskannya ke grep secara terpisah. Itu sudah dilakukan secara otomatis.

EDIT2: grepjuga harus mencetak hasilnya segera setelah ditemukan di aliran Tidak perlu streaming selesai sebelum Anda bisa mendapatkan hasil.

JoL
sumber
0

Mungkin Anda bisa "menggunakan grep pada semua input"? Menggunakan nc(netcat), atau melalui script, atau melalui alat lain yang serupa? Terutama jika patternfile Anda memiliki ukuran yang dapat dikelola (katakanlah kurang dari 1000 regexps).

Contoh pertama : Anda dapat egrepbeberapa koneksi streaming: (contoh di sini ditunjukkan dengan nc, tetapi yang lain bisa berlaku)

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

(catatan: Anda bahkan dapat: touch /some/path/results.gzsebelum memulai ncperintah, dan memiliki tail -ffile (kosong) itu untuk tidak melewatkan apa pun. Bagaimanapun, results.gz akan berisi semua yang ingin Anda tangkap)

contoh kedua : Anda bahkan bisa egreppada sesi shell yang sedang berjalan (dan menunjukkan cara lain untuk mengikuti perkembangan):

#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

egrepadalah versi yang sangat efisien grepuntuk sebagian besar sistem (lihat beberapa info interresting di: https://swtch.com/~rsc/regexp/regexp1.html )

Olivier Dulac
sumber
Anda bahkan dapat menggunakan contoh1 pada hal-hal seperti keluaran dd, dll.
Olivier Dulac
catatan sisi interresting: grep lebih efisien semakin besar bagian regexp yang diketahui (mis: mencari string atau regexp sjauh, bubur lebih lambat dari pencocokan somethingdan ini jauh lebih lambat daripada pencocokan something even much longer(yang terakhir memungkinkan pencocokan regexp untuk melompati lebih besar) bagian dari input ketika berbeda) Pada file besar, pada dasarnya "membagi" waktu untuk menguraikannya dengan rasio panjang (yaitu, menangkap 1 karakter yang dikenal hampir 40 kali lebih lambat daripada mencocokkan string 40 karakter yang dikenal. Saya tidak t prof it tetapi benar-benar terlihat.)
Olivier Dulac