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
$A
dan / atau$B
. Semakin besar Anda membuat angka-angka itu, semakin lambat akan diperoleh - tetapi Anda bisa membuatnya cukup besar.Anda dapat menggunakan
gnu grep
dengan-A
dan-B
untuk mencetak dengan tepat bagian-bagian dari file yang ingin Anda kecualikan tetapi tambahkan-n
sakelar untuk juga mencetak nomor baris dan kemudian format output dan berikan sebagai skrip perintahsed
untuk menghapus baris-baris itu:Ini juga harus bekerja dengan file pola dilewatkan ke
grep
via-f
misalnya:Saya pikir ini bisa sedikit dioptimalkan jika diciutkan tiga atau lebih nomor baris berturut-turut ke dalam rentang sehingga memiliki misalnya
2,6d
bukannya2d;3d;4d;5d;6d
... meskipun jika input hanya memiliki beberapa pertandingan, itu tidak layak dilakukan.Cara lain yang tidak mempertahankan urutan baris dan kemungkinan besar lebih lambat:
dengan
comm
:comm
membutuhkan input yang diurutkan yang berarti urutan baris tidak akan dipertahankan dalam output akhir (kecuali file Anda sudah diurutkan) sehingganl
digunakan untuk memberi nomor pada baris sebelum disortir ,comm -13
hanya mencetak baris yang unik ke FILE ke- 2 dan kemudiancut
menghapus bagian yang ditambahkan olehnl
(yaitu, bidang pertama dan pembatas:
)dengan
join
:sumber
comm
menjadi lebih cepat daripada yang asli dengansed
dangrep
?Jika Anda tidak keberatan menggunakan
vim
:-Nes
mengaktifkan mode ex yang tidak kompatibel, diam. Berguna untuk skrip.+{command}
beri tahu vim untuk dijalankan{command}
pada file.g/${PAT}/
- pada semua baris yang cocok/fff/
. Ini menjadi rumit jika polanya berisi ekspresi reguler karakter khusus yang tidak ingin Anda perlakukan seperti itu..-${B}
- dari 1 baris di atas yang ini.+${A}
- ke 2 baris di bawah ini (lihat:he cmdline-ranges
untuk dua ini)d
- hapus garis.+w !tee
kemudian menulis ke output standar.+q!
berhenti tanpa menyimpan perubahan.Anda dapat melewati variabel dan menggunakan pola dan angka secara langsung. Saya menggunakannya hanya untuk kejelasan tujuan.
sumber
Bagaimana dengan (menggunakan GNU
grep
danbash
):Di sini kita menemukan baris yang harus dibuang
grep -B2 -A1 'fff' file.txt
, kemudian menggunakan ini sebagai file input untuk menemukan baris yang diinginkan membuang ini.sumber
kos
(sekarang dihapus) seolah-olah ada garis duplikat dalam file input dan beberapa dari mereka berada di luar jangkauan dan yang lain di dalam kisaran itu akan menghapus semuanya. Juga, dengan beberapa kemunculan pola , jika ada baris seperti--
pada file input (di luar rentang) ini akan menghapusnya karena pembatas--
muncul dalamgrep
output ketika lebih dari satu baris adalah pola yang cocok (yang terakhir sangat tidak mungkin tetapi bernilai menyebutkan saya kira).Anda dapat mencapai hasil yang cukup baik dengan menggunakan file sementara:
Hasilnya cukup baik karena Anda dapat kehilangan beberapa lekukan dalam proses, tetapi jika itu adalah file sensitif xml atau indentasi itu seharusnya tidak menjadi masalah. Karena skrip ini menggunakan ram drive, menulis dan membaca file temp tersebut secepat bekerja di memori.
sumber
Selain itu, jika Anda hanya ingin mengecualikan beberapa baris di depan penanda yang diberikan, Anda dapat menggunakan:
(glenn jackman di /programming//a/1492538 )
Dengan memipipkan beberapa perintah, Anda bisa mendapatkan sebelum / sesudah behaivour:
sumber
awk
pada file terbalik untuk menangani baris berikut ketika Anda bermaksud untuk mempengaruhi baris sebelum dan membalikkan hasilnya.Salah satu cara untuk mencapai ini, mungkin cara termudah adalah dengan membuat variabel dan melakukan hal berikut:
Dengan cara ini Anda masih memiliki struktur Anda. Dan Anda dapat dengan mudah melihat dari liner apa yang ingin Anda hapus.
sumber
Jika hanya ada 1 kecocokan:
Jika tidak (awk):
sumber