Bagaimana saya bisa memotong file (aliran input dengan baik) sehingga saya hanya mendapatkan garis mulai dari kemunculan pola pertama hingga kemunculan pola foo
terakhir bar
?
Sebagai contoh, pertimbangkan input berikut:
A line
like
foo
this
foo
bar
something
something else
foo
bar
and
the
rest
Saya mengharapkan hasil ini:
foo
this
foo
bar
something
something else
foo
bar
text-processing
sed
rahmu
sumber
sumber
foo
dan terakhirbar
dan mencetak semuanya di antaranya, jika ada. Dengan stream Anda harus membaca sampai yang pertamafoo
, dan buffer semua baris berikutnya dalam memori sampai EOF, flushing buffer setiap kali abar
terlihat. Ini bisa berarti buffering seluruh aliran dalam memori.Jawaban:
Pencocokan pola sed
/first/,/second/
membaca baris satu per satu. Ketika beberapa baris cocok dengan/first/
itu akan mengingatnya dan berharap untuk pertandingan pertama untuk/second/
pola. Pada saat yang sama berlaku semua aktivitas yang ditentukan untuk pola itu. Setelah itu proses mulai lagi dan lagi hingga akhir file.Bukan itu yang kita butuhkan. Kita perlu melihat pencocokan
/second/
pola yang terakhir. Karena itu kami membangun konstruksi yang terlihat hanya untuk entri pertama/foo/
. Ketika ditemukan siklusa
dimulai. Kami menambahkan baris baru ke buffer pencocokan denganN
dan memeriksa apakah cocok dengan pola/bar/
. Jika ya, kita cukup mencetaknya dan menghapus buffer pertandingan dan janyway jump ke awal siklusba
.Kita juga perlu menghapus simbol baris baru setelah buffer dibersihkan
/^\n/s/^\n//
. Saya yakin ada solusi yang jauh lebih baik, sayangnya itu tidak muncul di benak saya.Semoga semuanya jelas.
sumber
sed
versi misalnya BSD sed (yang ditemukan pada Mac), tag harus diikuti oleh baris baru atau akhir string, jadi diperlukan penyesuaian berikut:sed -n -e '/foo/{:a' -e 'N;/^\n/s/^\n//;/bar/{p;s/.*//;};ba' -e '};'
Ini juga berfungsi pada GNU sed, jadi saya pikir modifikasi ini (multiple-e
args mengakhiri argumen setelah setiap nama cabang) adalah kebiasaan portabel yang baik untuk digunakan saat menggunakan cabang dalam sed.Saya akan melakukannya dengan Perl satu-liner kecil.
hasil panen
sumber
E
bukane
dan-00777
bukannya$/
bit (lihat perlrun (1)). Yang akan mempersingkat menjadi:,perl -0777 -nE 'say /(foo.*bar)/s'
masih bisa dibaca.-0[octal]
akan menemukan jalannya dalam alur kerja saya! Terima kasih untuk ituBerikut ini adalah solusi sed GNU dua lulus yang tidak memerlukan banyak memori:
Penjelasan
sed
Doa pertama melewati infile dan menemukan kejadian pertamafoo
dan semua kejadian berikutnyabar
.sed
skrip baru dengan dua doased
dan satutr
. Output yang ketigased
adalah[start_address],[end_address]p
, tanpa tanda kurung.sed
melewatiinfile
lagi, mencetak alamat yang ditemukan dan semuanya di antaranya.sumber
Jika file input cocok dengan nyaman dalam memori, tetap sederhana .
Jika file input sangat besar, Anda dapat menggunakannya
csplit
untuk memecahnya menjadi beberapa bagian pada bagian pertamafoo
dan setiap bagian selanjutnya,bar
kemudian mengumpulkan bagian-bagian tersebut. Potongan-potongan itu disebutpiece-000000000
,,piece-000000001
dll. Pilih awalan (di sini,piece-
) yang tidak akan berbenturan dengan file lain yang ada.(Pada sistem non-Linux, Anda harus menggunakan sejumlah besar di dalam kurung kurawal, misalnya
{999999999}
, dan meneruskan-k
opsi. Angka itu adalah jumlahbar
potongan.)Anda dapat mengumpulkan semua bagian dengan
cat piece-*
, tetapi ini akan memberi Anda segalanya setelah yang pertamafoo
. Jadi hapus bagian terakhir itu terlebih dahulu. Karena nama file yang dihasilkan olehcsplit
tidak mengandung karakter khusus, Anda dapat memperbaikinya tanpa mengambil tindakan pencegahan mengutip khusus, misalnya denganatau setara
Sekarang Anda dapat bergabung dengan semua bagian dan menghapus file-file sementara:
Jika Anda ingin menghapus potongan-potongan itu karena digabungkan untuk menghemat ruang disk, lakukan dalam satu lingkaran:
sumber
Inilah cara lain dengan
sed
:Ini menambahkan setiap baris dalam
/foo/,$
jangkauan (garis!
- garis yang tidak dalam kisaran inid
dihapus) keH
ruang lama. Baris yang tidak cocokbar
kemudian dihapus. Pada garis yang cocok, ruang pola dikosongkan, ex
diubah dengan ruang tahan dan garis kosong terkemuka di ruang pola dihapus.Dengan input besar dan beberapa kemunculan
bar
hal ini seharusnya (jauh) lebih cepat daripada menarik setiap garis ke dalam ruang pola dan kemudian, setiap kali, memeriksa ruang polabar
.Dijelaskan:
Tentu, jika ini adalah file (dan sesuai dengan memori) Anda bisa menjalankan:
karena
ed
bisa mencari maju dan mundur.Anda bahkan bisa membaca output perintah ke buffer teks jika shell Anda mendukung substitusi proses:
atau jika tidak, dengan
gnu ed
:sumber
Menggunakan awk dalam shell apa pun pada sistem UNIX dan tanpa membaca seluruh file atau input stream ke memori sekaligus:
sumber
Grep dapat melakukannya juga (well, GNU grep):
Untuk masukan dari badan pertanyaan:
sumber