don mungkin lebih baik dalam banyak kasus, tetapi untuk berjaga-jaga jika file tersebut sangat besar, dan Anda tidak seddapat menangani file skrip sebesar itu (yang dapat terjadi pada sekitar 5000 baris naskah) , ini dia dengan polos sed:
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Ini adalah contoh dari apa yang disebut jendela geser pada input. Ia bekerja dengan membangun tampak-depan penyangga dari $Bgaris -count sebelum pernah mencoba untuk mencetak apa pun.
Dan sebenarnya, mungkin saya harus mengklarifikasi poin saya sebelumnya: limiter kinerja utama untuk solusi ini dan don's akan langsung berhubungan dengan interval. Solusi ini akan melambat dengan ukuran interval yang lebih besar , sedangkan don's akan melambat dengan frekuensi interval yang lebih besar . Dengan kata lain, bahkan jika file input sangat besar, jika kejadian interval yang sebenarnya masih sangat jarang maka solusinya mungkin adalah cara untuk pergi. Namun, jika ukuran interval relatif dapat dikelola, dan cenderung sering terjadi, maka ini adalah solusi yang harus Anda pilih.
Jadi, inilah alur kerjanya:
- Jika
$matchditemukan di ruang pola yang didahului oleh \newline, sedsecara rekursif akan menghapus Dsetiap \newline yang mendahuluinya.
- Saya telah membersihkan
$matchruang pola sepenuhnya sebelumnya - tetapi untuk dengan mudah menangani tumpang tindih, meninggalkan tengara tampaknya bekerja jauh lebih baik.
- Saya juga mencoba
s/.*\n.*\($match\)/\1/mencoba mendapatkannya dalam sekali jalan dan menghindari loop, tetapi ketika $A/$Bbesar, Dloop elete terbukti jauh lebih cepat.
- Kemudian kami menarik
Ninput ext baris yang didahului oleh \npembatas ewline dan mencoba sekali lagi untuk Dmenghapus /\n.*$match/sekali lagi dengan merujuk ke ekspresi reguler kami yang terakhir digunakan w / //.
- Jika ruang pola cocok
$matchmaka hanya dapat melakukannya dengan $matchdi kepala garis - semua $Bgaris sebelumnya telah dihapus.
- Jadi kita mulai mengulang-ulang
$A.
- Setiap menjalankan loop ini kami akan mencoba untuk
s///ubstitute untuk &dirinya $Ath \nkarakter ewline di ruang pola, dan, jika berhasil, test akan cabang kami - dan kami seluruh $Aetelah penyangga - dari script sepenuhnya untuk memulai script lebih dari atas dengan jalur input berikutnya jika ada.
- Jika
test tidak berhasil, kami akan bkembali ke :tlabel op dan melakukan recurse untuk jalur input lain - mungkin memulai perulangan jika $matchterjadi saat mengumpulkan setelah itu $A.
- Jika kita bisa melewati
$matchlingkaran fungsi, maka kami akan mencoba untuk petak yang $baris terakhir jika ini itu, dan jika !tidak mencoba untuk s///ubstitute untuk &dirinya $Bth \nkarakter ewline di ruang pola.
- Kami juga akan
tmemperkirakan ini, dan jika berhasil kami akan mencabangkan ke :Plabel rintisan.
- Jika tidak kita akan bercabang kembali ke
:top dan mendapatkan baris input lain ditambahkan ke buffer.
- Jika kita membuatnya untuk
:Pmemecah kita akan Pmemecah kemudian Dmenghapus hingga baris pertama \ndi ruang pola dan menjalankan kembali skrip dari atas dengan apa yang tersisa.
Dan kali ini, jika kita lakukan A=2 B=2 match=5; seq 5 | sed...
Ruang pola untuk iterasi pertama di :Print akan terlihat seperti:
^1\n2\n3$
Dan begitulah cara sedmengumpulkan $Bbuffer sebelumnya. Dan jadi sedmencetak ke $B-count baris di belakang input yang telah dikumpulkan. Ini berarti bahwa, dengan contoh kita sebelumnya, sedakan Pmematikan 1untuk keluaran, dan kemudian Dmenghapusnya dan mengirim kembali ke atas skrip ruang pola yang terlihat seperti:
^2\n3$
... dan di bagian atas skrip, Nbaris input ekst diambil dan sehingga iterasi berikutnya terlihat seperti:
^2\n3\n4$
Jadi ketika kita menemukan kemunculan 5input pertama, ruang pola sebenarnya terlihat seperti:
^3\n4\n5$
Kemudian Dloop elete menendang dan ketika melalui itu terlihat seperti:
^5$
Dan ketika jalur Ninput ekst ditarik, sedhits EOF dan berhenti. Pada saat itu hanya ada Pjalur 1 dan 2.
Berikut ini contoh yang dijalankan:
A=8 B=7 match='[24689]0'
seq 100 |
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Itu mencetak:
1
2
3
4
5
6
7
8
9
10
11
12
29
30
31
32
49
50
51
52
69
70
71
72
99
100