Penghapusan header di tempat yang efisien untuk file besar menggunakan sed?


24

Perintah di bawah ini dapat memakan waktu beberapa menit tergantung pada ukuran file. Apakah ada metode yang lebih efisien?

sed -i 1d large_file 

Jawaban:


34

Coba edsebagai gantinya:

ed <<< $'1d\nwq' large_file

Jika "besar" itu berarti sekitar 10 juta baris atau lebih, lebih baik digunakan tail. Tidak dapat mengedit di tempat, tetapi kinerjanya membuat kekurangan itu dapat dimaafkan:

tail -n +2 large_file > large_file.new

Edit untuk menunjukkan beberapa perbedaan waktu:

( awkkode oleh Jaypal ditambahkan untuk memiliki waktu eksekusi pada mesin yang sama (CPU 2.2GHz).)

bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped

bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s

bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s

bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s

bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s

bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s

Dalam hal ini tail, saya lebih suka menghitung waktu untuk melakukan keduanya menghapus baris pertama dan ganti bigfile.txtdengan bigfile.new.
rozcietrzewiacz

@rozcietrzewiacz, poin Anda sudah benar. Terima kasih. Diperbarui.
manatwork

Ini sangat keren! Saya melakukan hal yang sama dengan awkdan mendapatkan hasil berikut -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
jaypal singh

1
@ Jaypal, saya menambahkan kode Anda ke daftar alternatif. Di mesin saya itu bahkan lebih cepat. Aneh, saya berharap awkkinerja lebih dekat sed. (Catatan untuk diri saya sendiri: jangan pernah mengharapkan - sebagai gantinya.)
manatwork

Ini adalah solusi terbaik dalam kasus saya: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;Saya menggunakan satu file dengan kunci untuk melacak daftar tugas tunggal yang digunakan oleh banyak proses. Saya mulai dengan apa poster awal yang digunakan: sed -i 1d large_file . Itu menyebabkan file terkunci selama 1-2 detik. The tail/mvcombo melengkapi hampir seketika. Terima kasih!
Chris Adams

6

Tidak ada cara untuk secara efisien menghapus sesuatu dari awal file. Menghapus data dari awal memerlukan penulisan ulang seluruh file.

Memotong dari ujung file bisa sangat cepat (OS hanya harus menyesuaikan informasi ukuran file, mungkin membersihkan blok yang sekarang tidak digunakan). Ini umumnya tidak mungkin ketika Anda mencoba untuk menghapus dari kepala file.

Secara teori ini bisa menjadi "cepat" jika Anda menghapus seluruh blok / luas tepat, tetapi tidak ada panggilan sistem untuk itu, jadi Anda harus mengandalkan semantik khusus sistem berkas (jika ada). (Atau memiliki beberapa bentuk offset di dalam blok / batas pertama untuk menandai awal sebenarnya file, saya kira. Tidak pernah mendengarnya juga.)


Jika file tersebut sangat besar, I / O overhead kemungkinan (mungkin jauh) lebih besar daripada overhead CPU yang diperlukan untuk memproses akhir baris.
Mat

Kamu benar. Namun mungkin ada perbedaan dalam cara alat mengakses konten file. Yang terbaik adalah tidak memproses baris demi baris saat tidak perlu atau setidaknya tidak membaca baris demi baris saat tidak perlu.
manatwork

2
Saya terkejut perbedaannya begitu besar dalam hasil Anda, dan dapat mereproduksinya dengan ukuran file itu di sini. Manfaatnya tampaknya berkurang karena ukuran file meningkat (dicoba dengan seq 10M, 15s untuk sed, 5s untuk ed). Tetap tips yang bagus (+1).
Mat

Dimulai dengan versi 3.15, Linux sekarang memiliki API untuk meruntuhkan bagian-bagian file pada sistem file berbasis luas, tetapi setidaknya untuk ext4 yang hanya dapat dilakukan pada blok penuh (biasanya 4k).
Stéphane Chazelas

Bahkan jika pengeditan mengharuskan penulisan ulang seluruh file, terkadang sangat berguna untuk memiliki alat baris perintah untuk mengedit secara efisien. Dalam kasus saya, ini membantu ketika saya harus menghapus baris pertama dari file yang lebih besar dari total RAM sistem saya.
Jason

3

Metode yang paling efisien, jangan lakukan itu! Jika Anda melakukannya, Anda perlu dua kali ruang 'besar' pada disk, dan Anda membuang IO.

Jika Anda terjebak dengan file besar yang ingin Anda baca tanpa baris 1, tunggu sampai Anda perlu membacanya untuk menghapus baris 1. Jika Anda perlu mengirim file dari stdin ke suatu program, gunakan tail untuk melakukannya:

tail -n +2 | your_program

Saat Anda perlu membaca file, Anda dapat mengambil kesempatan untuk menghapus baris 1, tetapi hanya jika Anda memiliki ruang yang dibutuhkan pada disk:

tail -n +2 | tee large_file2 | your_program

Jika Anda tidak dapat membaca dari stdin, gunakan fifo:

mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line

yang lebih baik lagi jika Anda menggunakan bash, manfaatkan penggantian proses:

your_program -i <(tail -n +2 large_file)

Jika Anda perlu mencari dalam file, saya tidak melihat solusi yang lebih baik daripada tidak terjebak dengan file di tempat pertama. Jika file ini dihasilkan oleh stdout:

large_file_generator | tail -n +2 > large_file

Selain itu, selalu ada solusi pengganti fifo atau proses:

mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file

large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)

1

Anda dapat menggunakan Vim dalam mode Ex:

ex -sc '1d|x' large_file
  1. 1 pilih baris pertama

  2. d menghapus

  3. x Simpan dan tutup


0

Ini hanya berteori, tapi ...

Sistem file khusus (diimplementasikan menggunakan FUSE atau mekanisme serupa) dapat mengekspos direktori yang isinya persis sama dengan direktori yang sudah ada di tempat lain, tetapi dengan file terpotong sesuai keinginan. Sistem file akan menerjemahkan semua offset file. Maka Anda tidak perlu melakukan penulisan ulang file yang memakan waktu.

Tetapi mengingat ide ini sangat tidak sepele, kecuali Anda punya puluhan terabyte file seperti itu, menerapkan sistem file seperti itu akan terlalu mahal / memakan waktu untuk menjadi praktis.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.