Kecuali jika segmen Anda sangat besar (seperti pada: Anda benar-benar tidak dapat menyimpan banyak RAM, mungkin karena ini adalah sistem tertanam kecil yang mengendalikan sistem file besar), satu pass adalah pendekatan yang lebih baik. Bukan hanya karena itu akan lebih cepat, tetapi yang paling penting karena memungkinkan sumber untuk menjadi aliran, dari mana data membaca dan tidak disimpan hilang. Ini benar-benar pekerjaan untuk awk, meskipun sed bisa melakukannya juga.
sed -n -e 's/^---$//' -e 't a' \
-e 'H' -e '$g' -e '$s/^\n//' -e '$p' -e 'b' \
-e ':a' -e 'h' # you are not expected to understand this
awk '{if (/^---$/) {chunk=""} # separator ==> start new chunk
else {chunk=chunk $0 RS}} # append line to chunk
END {printf "%s", chunk}' # print last chunk (without adding a newline)
Jika Anda harus menggunakan pendekatan dua lintasan, tentukan offset garis pemisah terakhir dan cetak dari itu. Atau tentukan byte offset dan cetak dari itu.
</input/file tail -n +$((1 + $(</input/file # print the last N lines, where N=…
grep -n -e '---' | # list separator line numbers
tail -n 1 | # take the last one
cut -d ':' -f 1) )) # retain only line number
</input/file tail -n +$(</input/file awk '/^---$/ {n=NR+1} END {print n}')
</input/file tail -c +$(</input/file LC_CTYPE=C awk '
{pos+=length($0 RS)} # pos contains the current byte offset in the file
/^---$/ {last=pos} # last contains the byte offset after the last separator
END {print last+1} # print characters from last (+1 because tail counts from 1)
')
Tambahan: Jika Anda memiliki lebih dari POSIX, berikut ini adalah versi sekali jalan sederhana yang bergantung pada ekstensi umum untuk awk yang memungkinkan pemisah rekaman RS
menjadi ekspresi reguler (POSIX hanya mengizinkan satu karakter). Itu tidak sepenuhnya benar: jika file berakhir dengan pemisah rekaman, ia mencetak potongan sebelum pemisah rekaman terakhir, bukan catatan kosong. Versi kedua menggunakan RT
menghindari yang cacat, tetapi RT
khusus untuk GNU awk.
awk -vRS='(^|\n)---+($|\n)' 'END{printf $0}'
gawk -vRS='(^|\n)---+($|\n)' 'END{if (RT == "") printf $0}'
Gilles 'SANGAT berhenti menjadi jahat'
sumber
sed
berfungsi dengan baik, tapi saya tidak bisa mendapatkanawk
contoh untuk dijalankan; hang ... dan saya mendapatkan kesalahan pada contoh ke-3:cut -f ':' -t 1
... cut: opsi tidak valid - 't'cut
contoh. Saya melihat tidak ada yang salah denganawk
contoh, versi awk apa yang Anda gunakan, dan apa input pengujian Anda?awk
versi ini berfungsi .. ini hanya memakan waktu yang sangat lama pada file besar ..sed
versi memproses file yang sama dalam 0,470an .. Data pengujian saya sangat berbobot ... hanya dua potongan dengan satu-satunya '---' tiga baris dari akhir 1 juta baris ...Strategi dua lulus tampaknya menjadi hal yang benar. Alih-alih sed saya akan menggunakan
awk(1)
. Dua operan bisa terlihat seperti ini:untuk mendapatkan nomor baris. Dan kemudian gema semua teks mulai dari nomor baris itu dengan:
Seharusnya ini tidak membutuhkan buffering yang berlebihan.
sumber
awk -v line=$(awk '/^---$/{n=NR}END{print n}' file) 'NR>line' file
Nomor
sed
baris ouputs pertama dari baris "---" ...Yang kedua
sed
mengekstrak angka terakhir dari output sed pertama ...Tambahkan 1 ke nomor itu untuk memulai blok "ccc" Anda ...
Yang ketiga output 'sed' dari awal blok "ccc" ke EOF
Perbarui (dengan info yang diubah metode Gilles)
Yah saya bertanya-tanya tentang bagaimana kinerja glenn jackman
tac
, jadi saya menguji waktu tiga jawaban (pada saat penulisan) ... File uji masing-masing berisi 1 juta baris (dari nomor baris mereka sendiri).Semua jawaban melakukan apa yang diharapkan ...
Inilah saatnya ..
Gilles
sed
(single pass)Gilles
awk
(single pass)Gilles 'two-pass' (metode pertama)
Gilles 'two-pass' (metode kedua) ... sangat cepat
Gilles 'two-pass' (metode ketiga)
Gilles 'gawk' (metode RT) ... sangat cepat , tetapi bukan POSIX.
glenn jackman ... sangat cepat , tetapi tidak POSIX.
fred.bear
Mackie Messer
sumber
Gunakan " tac " yang menampilkan baris file dari ujung ke awal:
sumber
tac
bukan POSIX, itu Linux-spesifik (itu di GNU coreutils, dan di beberapa instalasi busybox).Anda bisa menggunakannya
ed
Cara kerjanya:
t
menduplikasi baris saat ini (.
) - yang selalu merupakan baris terakhir saated
dimulai (kalau-kalau pembatas hadir di baris terakhir),1,?===?d
hapus semua baris hingga dan termasuk pertandingan sebelumnya (ed
masih di baris terakhir) ) kemudian$d
menghapus baris terakhir (duplikat),,p
mencetak buffer teks (ganti denganw
untuk mengedit file pada tempatnya) dan akhirnyaq
berhentied
.Jika Anda tahu ada setidaknya satu pembatas di input (dan tidak peduli apakah itu juga dicetak) maka
akan menjadi lebih pendek.
Cara kerjanya: itu menambahkan semua baris ke
H
buffer lama, itu menimpah
buffer lama ketika menemukan kecocokan, itud
menghapus semua baris kecuali yang$
t ketikax
mengubah buffer (dan cetak otomatis).sumber