don mungkin lebih baik dalam banyak kasus, tetapi untuk berjaga-jaga jika file tersebut sangat besar, dan Anda tidak sed
dapat 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 $B
garis -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
$match
ditemukan di ruang pola yang didahului oleh \n
ewline, sed
secara rekursif akan menghapus D
setiap \n
ewline yang mendahuluinya.
- Saya telah membersihkan
$match
ruang 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/$B
besar, D
loop elete terbukti jauh lebih cepat.
- Kemudian kami menarik
N
input ext baris yang didahului oleh \n
pembatas ewline dan mencoba sekali lagi untuk D
menghapus /\n.*$match/
sekali lagi dengan merujuk ke ekspresi reguler kami yang terakhir digunakan w / //
.
- Jika ruang pola cocok
$match
maka hanya dapat melakukannya dengan $match
di kepala garis - semua $B
garis sebelumnya telah dihapus.
- Jadi kita mulai mengulang-ulang
$A
.
- Setiap menjalankan loop ini kami akan mencoba untuk
s///
ubstitute untuk &
dirinya $A
th \n
karakter ewline di ruang pola, dan, jika berhasil, t
est akan cabang kami - dan kami seluruh $A
etelah penyangga - dari script sepenuhnya untuk memulai script lebih dari atas dengan jalur input berikutnya jika ada.
- Jika
t
est tidak berhasil, kami akan b
kembali ke :t
label op dan melakukan recurse untuk jalur input lain - mungkin memulai perulangan jika $match
terjadi saat mengumpulkan setelah itu $A
.
- Jika kita bisa melewati
$match
lingkaran fungsi, maka kami akan mencoba untuk p
etak yang $
baris terakhir jika ini itu, dan jika !
tidak mencoba untuk s///
ubstitute untuk &
dirinya $B
th \n
karakter ewline di ruang pola.
- Kami juga akan
t
memperkirakan ini, dan jika berhasil kami akan mencabangkan ke :P
label rintisan.
- Jika tidak kita akan bercabang kembali ke
:t
op dan mendapatkan baris input lain ditambahkan ke buffer.
- Jika kita membuatnya untuk
:P
memecah kita akan P
memecah kemudian D
menghapus hingga baris pertama \n
di 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 :P
rint akan terlihat seperti:
^1\n2\n3$
Dan begitulah cara sed
mengumpulkan $B
buffer sebelumnya. Dan jadi sed
mencetak ke $B
-count baris di belakang input yang telah dikumpulkan. Ini berarti bahwa, dengan contoh kita sebelumnya, sed
akan P
mematikan 1
untuk keluaran, dan kemudian D
menghapusnya dan mengirim kembali ke atas skrip ruang pola yang terlihat seperti:
^2\n3$
... dan di bagian atas skrip, N
baris input ekst diambil dan sehingga iterasi berikutnya terlihat seperti:
^2\n3\n4$
Jadi ketika kita menemukan kemunculan 5
input pertama, ruang pola sebenarnya terlihat seperti:
^3\n4\n5$
Kemudian D
loop elete menendang dan ketika melalui itu terlihat seperti:
^5$
Dan ketika jalur N
input ekst ditarik, sed
hits EOF dan berhenti. Pada saat itu hanya ada P
jalur 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