Saya memiliki situasi unik di mana saya dapat membandingkan solusi yang diusulkan pada halaman ini, jadi saya menulis jawaban ini sebagai konsolidasi dari solusi yang diusulkan dengan menyertakan waktu berjalan untuk masing-masing.
Mendirikan
Saya memiliki file data teks ASCII 3,261 gigabyte dengan satu pasangan nilai kunci per baris. File ini berisi total 3.339.550.320 baris dan menentang pembukaan di editor apa pun yang saya coba, termasuk masuk ke Vim saya. Saya perlu mengatur ulang file ini untuk menyelidiki beberapa nilai yang saya temukan hanya sekitar baris ~ 500.000.000.
Karena file memiliki begitu banyak baris:
- Saya perlu mengekstrak hanya sebagian dari baris untuk melakukan sesuatu yang berguna dengan data.
- Membaca setiap baris yang mengarah ke nilai-nilai yang saya pedulikan akan memakan waktu lama.
- Jika solusinya membaca melewati baris yang saya pedulikan dan terus membaca sisa file itu akan membuang waktu membaca hampir 3 miliar baris yang tidak relevan dan memakan waktu 6x lebih lama dari yang diperlukan.
Skenario terbaik saya adalah solusi yang mengekstrak hanya satu baris dari file tanpa membaca baris lain dalam file, tetapi saya tidak bisa memikirkan bagaimana saya akan mencapai ini di Bash.
Untuk keperluan kewarasan saya, saya tidak akan mencoba membaca 500.000.000 baris penuh yang saya butuhkan untuk masalah saya sendiri. Sebaliknya saya akan mencoba untuk mengekstrak baris 50.000.000 dari 3.339.550.320 (yang berarti membaca file lengkap akan memakan waktu 60x lebih lama dari yang diperlukan).
Saya akan menggunakan time
built-in untuk benchmark setiap perintah.
Baseline
Pertama mari kita lihat bagaimana head
tail
solusinya:
$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0
real 1m15.321s
Garis dasar untuk baris 50 juta adalah 00: 01: 15.321, jika saya langsung ke baris 500 juta mungkin akan ~ 12,5 menit.
memotong
Saya ragu dengan yang ini, tapi patut dicoba:
$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0
real 5m12.156s
Yang ini membutuhkan waktu 00: 05: 12.156 untuk berjalan, yang jauh lebih lambat dari baseline! Saya tidak yakin apakah itu membaca seluruh file atau hanya hingga 50 juta baris sebelum berhenti, tetapi terlepas dari ini sepertinya bukan solusi yang layak untuk masalah ini.
AWK
Saya hanya menjalankan solusi dengan exit
karena saya tidak akan menunggu file lengkap berjalan:
$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0
real 1m16.583s
Kode ini berjalan pada 00: 01: 16.583, yang hanya lebih lambat ~ 1 detik, tetapi masih belum ada perbaikan pada baseline. Pada tingkat ini jika perintah keluar telah dikecualikan mungkin akan memakan waktu sekitar ~ 76 menit untuk membaca seluruh file!
Perl
Saya menjalankan solusi Perl yang ada juga:
$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0
real 1m13.146s
Kode ini berjalan di 00: 01: 13.146, yang ~ 2 detik lebih cepat dari baseline. Jika saya menjalankannya pada 500.000.000 penuh mungkin akan memakan waktu ~ 12 menit.
sed
Jawaban teratas di papan tulis, inilah hasil saya:
$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0
real 1m12.705s
Kode ini berjalan di 00: 01: 12.705, yang 3 detik lebih cepat dari garis dasar, dan ~ 0,4 detik lebih cepat dari Perl. Jika saya menjalankannya pada baris 500.000.000 penuh mungkin akan memakan waktu ~ 12 menit.
mapfile
Saya memiliki bash 3.1 dan karenanya tidak dapat menguji solusi mapfile.
Kesimpulan
Sepertinya, sebagian besar, sulit untuk memperbaiki head
tail
solusinya. Paling-paling sed
solusi ini memberikan peningkatan efisiensi ~ 3%.
(persentase dihitung dengan rumus % = (runtime/baseline - 1) * 100
)
Baris 50,000,000
- 00: 01: 12.705 (-00: 00: 02.616 = -3.47%)
sed
- 00: 01: 13.146 (-00: 00: 02.175 = -2.89%)
perl
- 00: 01: 15.321 (+00: 00: 00.000 = + 0,00%)
head|tail
- 00: 01: 16.583 (+00: 00: 01.262 = + 1,68%)
awk
- 00: 05: 12.156 (+00: 03: 56.835 = + 314.43%)
cut
Baris 500.000.000
- 00: 12: 07.050 (-00: 00: 26.160)
sed
- 00: 12: 11.460 (-00: 00: 21.750)
perl
- 00: 12: 33.210 (+00: 00: 00.000)
head|tail
- 00: 12: 45.830 (+00: 00: 12.620)
awk
- 00: 52: 01.560 (+00: 40: 31.650)
cut
Baris 3.338.559.320
- 01: 20: 54.599 (-00: 03: 05.327)
sed
- 01: 21: 24.045 (-00: 02: 25.227)
perl
- 01: 23: 49.273 (+00: 00: 00.000)
head|tail
- 01: 25: 13.548 (+00: 02: 35.735)
awk
- 05: 47: 23.026 (+04: 24: 26.246)
cut
awk
dansed
dan saya yakin seseorang dapat datang dengan Perl one-liner atau lebih;)