Saya perlu berulang kali menghapus baris pertama dari file teks besar menggunakan skrip bash.
Saat ini saya menggunakan sed -i -e "1d" $FILE
- tetapi butuh sekitar satu menit untuk melakukan penghapusan.
Apakah ada cara yang lebih efisien untuk mencapai ini?
Jawaban:
Coba ekor :
-n x
: Cukup cetakx
baris terakhir .tail -n 5
akan memberi Anda 5 baris terakhir dari input. The+
tanda jenis membalikkan argumen dan maketail
apapun cetak tetapi yang pertamax-1
garis.tail -n +1
akan mencetak seluruh file,tail -n +2
semuanya kecuali baris pertama, dll.GNU
tail
jauh lebih cepat daripadased
.tail
juga tersedia di BSD dan-n +2
bendera konsisten di kedua alat. Periksa halaman manual FreeBSD atau OS X untuk informasi lebih lanjut.Versi BSD bisa lebih lambat dari itu
sed
. Saya bertanya-tanya bagaimana mereka mengaturnya;tail
seharusnya hanya membaca file baris demi baris sementarased
melakukan operasi yang cukup kompleks yang melibatkan menafsirkan skrip, menerapkan ekspresi reguler dan sejenisnya.Catatan: Anda mungkin tergoda untuk menggunakannya
tetapi ini akan memberi Anda file kosong . Alasannya adalah bahwa pengalihan (
>
) terjadi sebelumtail
dipanggil oleh shell:$FILE
tail
tail
proses ke$FILE
tail
membaca dari sekarang kosong$FILE
Jika Anda ingin menghapus baris pertama di dalam file, Anda harus menggunakan:
The
&&
akan memastikan bahwa file tidak ditimpa ketika ada masalah.sumber
-r
opsi. Mungkin ada pengaturan buffer di suatu tempat di sistem? Atau-n
nomor 32-bit yang ditandatangani?tail
akan bekerja untuk ukuran file apa pun.-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Anda dapat menggunakan -i untuk memperbarui file tanpa menggunakan operator '>'. Perintah berikut akan menghapus baris pertama dari file dan menyimpannya ke file.
sumber
unterminated transform source string
sed -i '1,2d' filename
tail -n +2
. Tidak yakin mengapa itu bukan jawaban teratas.Bagi mereka yang menggunakan SunOS yang bukan GNU, kode berikut akan membantu:
sumber
Tidak, itu seefisien yang akan Anda dapatkan. Anda bisa menulis program C yang bisa melakukan pekerjaan sedikit lebih cepat (lebih sedikit waktu startup dan pemrosesan argumen) tetapi mungkin akan cenderung ke kecepatan yang sama seperti sed file menjadi besar (dan saya menganggap mereka besar jika butuh satu menit ).
Tetapi pertanyaan Anda menderita masalah yang sama seperti banyak orang lain karena itu pra-mengandaikan solusi. Jika Anda memberi tahu kami secara terperinci apa yang Anda coba lakukan daripada bagaimana caranya , kami mungkin dapat menyarankan opsi yang lebih baik.
Misalnya, jika ini adalah file A yang diproses oleh beberapa program B lainnya, salah satu solusinya adalah tidak menghapus baris pertama, tetapi memodifikasi program B untuk memprosesnya secara berbeda.
Katakanlah semua program Anda ditambahkan ke file A ini dan program B saat ini membaca dan memproses baris pertama sebelum menghapusnya.
Anda dapat merekayasa ulang program B sehingga tidak mencoba menghapus baris pertama tetapi mempertahankan offset (mungkin berbasis file) yang persisten ke dalam file A sehingga, saat dijalankan, program dapat mencari proses offset itu, baris di sana, dan perbarui offset.
Kemudian, pada waktu tenang (tengah malam?), Ia bisa melakukan pemrosesan khusus file A untuk menghapus semua baris yang saat ini diproses dan mengatur offset kembali ke 0.
Tentunya akan lebih cepat bagi suatu program untuk membuka dan mencari file daripada membuka dan menulis ulang. Diskusi ini mengasumsikan Anda memiliki kendali atas program B, tentu saja. Saya tidak tahu apakah itu masalahnya tetapi mungkin ada solusi lain yang mungkin jika Anda memberikan informasi lebih lanjut.
sumber
awk FNR-1 *.csv
mungkin lebih cepat.Anda dapat mengedit file di tempat: Cukup gunakan
-i
bendera perl , seperti ini:Ini membuat baris pertama menghilang, seperti yang Anda tanyakan. Perl perlu membaca dan menyalin seluruh file, tetapi mengatur agar output disimpan dengan nama file asli.
sumber
Anda dapat dengan mudah melakukan ini dengan:
di baris perintah; atau untuk menghapus baris pertama file secara permanen, gunakan mode sed di tempat dengan
-i
bendera:sumber
Seperti yang dikatakan Pax, Anda mungkin tidak akan mendapatkan yang lebih cepat dari ini. Alasannya adalah bahwa hampir tidak ada sistem file yang mendukung pemotongan sejak awal file sehingga ini akan menjadi operasi O (
n
) di manan
ukuran file. Apa yang dapat Anda lakukan jauh lebih cepat adalah menimpa baris pertama dengan jumlah byte yang sama (mungkin dengan spasi atau komentar) yang mungkin bekerja untuk Anda tergantung pada apa yang Anda coba lakukan (apa itu omong-omong?).sumber
The
sponge
util menghindari kebutuhan untuk menyulap file temp:sumber
sponge
memang jauh lebih bersih dan lebih kuat daripada solusi yang diterima (tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)sponge
buffer seluruh file dalam memori? Itu tidak akan berfungsi jika itu adalah ratusan GB.sponge
akan menyerapnya, karena ia menggunakan file / tmp sebagai langkah perantara, yang kemudian digunakan untuk mengganti yang asli sesudahnya.Jika Anda ingin memodifikasi file di tempat, Anda selalu bisa menggunakan yang asli
ed
bukan yang s penerus treamingsed
:The
ed
perintah adalah asli editor teks UNIX, sebelum ada bahkan terminal layar penuh, workstation apalagi grafis. Theex
Editor, dikenal sebagai apa yang Anda gunakan saat mengetik di usus promptvi
, adalah mantan versi cenderung daried
, begitu banyak pekerjaan perintah yang sama. Meskipuned
dimaksudkan untuk digunakan secara interaktif, itu juga dapat digunakan dalam mode batch dengan mengirimkan serangkaian perintah ke sana, yang merupakan apa yang dilakukan solusi ini.Urutan
<<<$'1d\nwq\n'
mengambil keuntungan dari dukungan Bash karena di sini-string (<<<
) dan kutipan POSIX ($'
...'
) untuk masukan pakan keed
perintah yang terdiri dari dua baris:1d
yang d eletes baris 1 , dan kemudianwq
, yang w ritus file kembali ke disk dan kemudian q UITS sesi editing.sumber
harus menunjukkan baris kecuali baris pertama:
sumber
Bisa menggunakan vim untuk melakukan ini:
Ini harus lebih cepat, karena vim tidak akan membaca seluruh file saat diproses.
sumber
+wq!
jika shell Anda bash. Mungkin bukan karena!
tidak pada awal kata, tetapi membiasakan diri mengutip sesuatu mungkin baik di sekitar. (Dan jika Anda menginginkan efisiensi super dengan tidak mengutip yang tidak perlu, Anda tidak perlu mengutipnya1d
juga.)Bagaimana dengan menggunakan csplit?
sumber
csplit file /^.*$/1
. Atau lebih sederhana:csplit file //1
. Atau bahkan lebih sederhana:csplit file 2
.Karena sepertinya saya tidak bisa mempercepat penghapusan, saya pikir pendekatan yang baik mungkin untuk memproses file dalam batch seperti ini:
Kelemahan dari ini adalah bahwa jika program terbunuh di tengah (atau jika ada sql buruk di sana - menyebabkan bagian "proses" mati atau terkunci), akan ada garis yang dilewati, atau diproses dua kali .
(file1 berisi baris kode sql)
sumber
Jika yang ingin Anda lakukan adalah memulihkan setelah kegagalan, Anda bisa saja membangun file yang telah Anda lakukan sejauh ini.
sumber
Liner satu ini akan melakukan:
Berhasil, karena
tail
dijalankan sebelumecho
dan kemudian file dibuka, maka tidak perlu untuk file temp.sumber
Apakah menggunakan tail pada baris N-1 dan mengarahkannya ke file, diikuti dengan menghapus file lama, dan mengganti nama file baru ke nama lama melakukan pekerjaan?
Jika saya melakukan ini secara terprogram, saya akan membaca file, dan mengingat file offset, setelah membaca setiap baris, sehingga saya dapat mencari kembali ke posisi itu untuk membaca file dengan satu baris lebih sedikit di dalamnya.
sumber