Menggunakan 'head' atau 'tail' pada file teks BESAR - 19 GB

14

Saya memiliki masalah dengan melihat potongan file teks yang sangat besar. File ini, sekitar 19 GB, jelas terlalu besar untuk dilihat dengan cara tradisional apa pun.

Saya telah mencoba head 1dan tail 1( head -n 1dan tail -n 1) dengan kedua perintah disalurkan bersama dalam berbagai cara (untuk mendapatkan bagian di tengah) tanpa hasil. Mesin Linux saya yang menjalankan Ubuntu 9.10 tidak dapat memproses file ini.

Bagaimana cara saya menangani file ini? Tujuan utama saya adalah mengasah jalur 45000000 dan 45000100.

nicorellius
sumber
Berpikir untuk menulis skrip Python cepat untuk membaca baris dan mencetak yang saya perlu file, tapi saya bisa membayangkan ini butuh waktu lama ...
nicorellius
Apakah semua garis memiliki panjang yang sama?
Paul
@ Paul - sayangnya, panjangnya tidak sama.
nicorellius
Anda dapat mencoba splitmembuat file besar lebih mudah untuk dikerjakan.
iglvzx
1
Baik. Pemrosesan file sebesar itu akan membutuhkan waktu, jadi jawaban di bawah ini akan membantu itu. Jika Anda ingin mengekstrak hanya bagian yang Anda cari dan dapat memperkirakan kira-kira di mana ia dapat Anda gunakan dduntuk mendapatkan bagian yang Anda cari. Misalnya dd if=bigfile of=extractfile bs=1M skip=10240 count=5akan mengekstrak 5MB dari file mulai dari titik 10GB.
Paul

Jawaban:

11

Anda harus menggunakan sed.

sed -n -e 45000000,45000100p -e 45000101q bigfile > savedlines

Ini memberitahu Anda seduntuk mencetak baris 45000000-45000100 inklusif, dan untuk berhenti pada jalur 45000101.

Kyle Jones
sumber
1
Ini masih sangat lambat, hampir seperti head -45000000,45000100p bigfile | ekor -100> savelines
Dmitry Polushkin
tail+|headlebih cepat dengan 10-15% baik.
Erich
4

Buat database MySQL dengan tabel tunggal yang memiliki bidang tunggal. Kemudian impor file Anda ke dalam basis data. Ini akan membuatnya sangat mudah untuk mencari garis tertentu.

Saya tidak berpikir hal lain bisa lebih cepat (jika headdan tailsudah gagal). Pada akhirnya, aplikasi yang ingin mencari baris nharus mencari melalui seluruh file hingga ditemukan nbaris baru. Tanpa semacam pencarian (indeks-baris ke byte diimbangi ke dalam file) tidak ada kinerja yang lebih baik dapat dicapai.

Mengingat betapa mudahnya membuat database MySQL dan mengimpor data ke dalamnya, saya merasa ini adalah pendekatan yang layak.

Inilah cara melakukannya:

DROP DATABASE IF EXISTS helperDb;
CREATE DATABASE `helperDb`;
CREATE TABLE `helperDb`.`helperTable`( `lineIndex` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `lineContent` MEDIUMTEXT , PRIMARY KEY (`lineIndex`) );
LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable (lineContent);
SELECT lineContent FROM helperTable WHERE ( lineIndex > 45000000 AND lineIndex < 45000100 );

/tmp/my_large_file akan menjadi file yang ingin Anda baca.

Sintaks yang benar untuk mengimpor file dengan nilai batas-tab pada setiap baris, adalah:

LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable FIELDS TERMINATED BY '\n' (lineContent);

Keuntungan utama lainnya adalah, jika nanti Anda memutuskan untuk mengekstrak rangkaian baris lain, Anda tidak perlu menunggu berjam-jam untuk pemrosesan lagi (kecuali jika Anda menghapus database tentu saja).

Der Hochstapler
sumber
Jadi ini memang solusi yang bagus. Saya mendapatkannya untuk bekerja dengan sedperintah di bawah ini, dan mengidentifikasi baris saya. Tapi sekarang saya punya pertanyaan lanjutan bahwa metode basis data mungkin lebih cocok. Saya sekarang perlu menghapus beberapa ratus baris dari file.
nicorellius
Saya yakin sedbisa melakukan itu juga. Tentu saja, jika Anda memiliki data dalam database itu akan sepele untuk mengekspor file baru hanya dengan baris yang Anda inginkan.
Der Hochstapler
Terima kasih lagi. Saya mengambil sedjawabannya (karena itu memberi saya kesenangan lebih cepat; -) tetapi memberi Anda suara karena saya akan menggunakan metode Anda di masa depan. Saya menghargainya.
nicorellius
1
Anda dapat mencoba menambahkan FIELDS TERMINATED BY '\n'ke LOAD DATAbaris.
Der Hochstapler
1
Maaf, ada kesalahan dalam kode saya. Saya juga menambahkan sintaks yang benar untuk kasus Anda (diuji kali ini).
Der Hochstapler
1

Dua alat tua yang bagus untuk file besar adalah joindan split. Anda dapat menggunakan --lines=<number>opsi split with yang memotong file ke beberapa file dengan ukuran tertentu.

Sebagai contoh split --lines=45000000 huge_file.txt. Bagian yang dihasilkan akan berada di xa, xb, dll. Kemudian Anda dapat headbagian xb yang akan mencakup baris yang Anda inginkan. Anda juga dapat 'bergabung' file kembali ke file besar tunggal.

Anssi
sumber
Luar biasa, terima kasih, saya benar-benar lupa tentang perintah split.
siliconrockstar
0

Anda memiliki alat yang tepat tetapi tidak menggunakannya dengan benar. Seperti yang sebelumnya dijawab di U&L, tail -n +X file | head -n Y(perhatikan +) adalah 10-15% lebih cepat daripada seduntuk garis Y mulai dari X. Dan mudahnya, Anda tidak perlu secara eksplisit exitprosesnya seperti sed.

tail akan membaca dan membuang garis X-1 pertama (tidak ada jalan lain untuk itu), kemudian membaca dan mencetak baris berikut. head akan membaca dan mencetak jumlah baris yang diminta, kemudian keluar. Ketika head keluar, tail menerima sinyal SIGPIPE dan mati, sehingga tidak akan membaca lebih dari nilai ukuran buffer (biasanya beberapa kilobyte) garis dari file input.

Erich
sumber