Saya memiliki file yang berisi sekitar 10 juta baris.
Saya ingin menghapus semua baris dalam file yang kurang dari enam karakter.
Bagaimana saya melakukan ini?
command-line
text-processing
TellMeWhy
sumber
sumber
Jawaban:
Ada banyak cara untuk melakukan ini.
Menggunakan
grep
:Sekarang
out.txt
akan berisi garis yang memiliki enam karakter atau lebih.Cara sebaliknya:
Menggunakan
sed
, menghapus garis dengan panjang 5 atau kurang:Cara sebaliknya, mencetak garis dengan panjang enam atau lebih:
Anda dapat menyimpan output di file yang berbeda menggunakan
>
operator sukagrep
atau mengedit file di tempat menggunakan-i
opsised
:File asli akan dicadangkan
file.txt.bak
dan file yang diubah akanfile.txt
.Jika Anda tidak ingin menyimpan cadangan:
Menggunakan shell, Slower, Don't do this , ini hanya demi menunjukkan metode lain:
Menggunakan
python
, bahkan lebih lambat darigrep
,sed
:Lebih baik gunakan daftar pemahaman agar lebih Pythonic:
sumber
Ini sangat sederhana:
Ini sangat efisien, karena
grep
tidak akan mencoba mem-parsing lebih dari yang dibutuhkannya, atau menafsirkan karakter dengan cara apa pun: ia hanya mengirim garis (keseluruhan) ke stdout (yang kemudian diarahkan oleh shell ke file yang dihasilkan) segera setelah ia melihat 6 karakter pada baris itu (.
dalam konteks regexp cocok dengan 1 karakter apa pun).Jadi grep hanya akan menghasilkan baris yang memiliki 6 (atau lebih) karakter, dan yang lainnya tidak dihasilkan oleh grep sehingga mereka tidak membuatnya menjadi filefile.
sumber
Solusi # 1: menggunakan C
Cara tercepat: kompilasi dan jalankan program C ini:
Kompilasi dengan
gcc program.c -o program
, jalankan dengan./program file line_length
(di manafile
= path ke file danline_length
= panjang garis minimum, dalam kasus Anda6
; panjang garis maksimum dibatasi untuk1000000
karakter per baris; Anda dapat mengubahnya dengan mengubah nilaiMAX_BUFFER_SIZE
).(Trik untuk mengganti
\n
dengan yang\0
ditemukan di sini .)Perbandingan dengan semua solusi lain yang diajukan untuk pertanyaan ini kecuali solusi shell (uji coba pada file ~ 91MB dengan garis 10M dengan panjang rata-rata 8 karakter):
Solusi # 2: menggunakan AWK:
length>=6
: jikalength>=6
mengembalikan TRUE, mencetak catatan saat ini.Solusi # 3: menggunakan Perl:
lenght>=6
mengembalikan TRUE, cetak catatan saat ini.sumber
awk
..sed
solusi saya (itu terjadi, saya tahu). XDpos
variabel? Saya mendapatkannya mengembalikan pointer ke karakterline
dengan karakter baris baru, tetapi Anda sepertinya tidak pernah menggunakannya. Dan jika Anda tidak menemukannya, Anda hanya mengaturnya sama dengan\0
.\0
(strchr()
mengembalikan pointer NULL jika karakter tidak ditemukan). Intinya adalah mengganti setiap baris baru di akhir setiap baris dengan\0
sehingga baris baru tidak pernah dihitung olehstrlen()
: ini adalah agar panjangnya selalu dapat dibandingkan dengan 6 terlepas dari potensi baris baru yang hilang pada baris terakhir. Mengobati secara berbeda hanya baris terakhir yang akan jauh lebih efisien, saya tahu. Saya mungkin akan memperbaruinya nanti.grep
solusi pada file yang sama dan sebenarnya lebih cepat (mungkin karenastrlen()
bukan ide terbaik di sini) . Saya akan mencoba menggunakangetchar()
loop untuk memeriksa hanya karakter N pertama sebagai gantinya, saya kira itu harus meningkatkan itu terlihat. Dan ya, setiap garis di atas panjang buffer hanya dipotong sesuai panjang buffer.Anda dapat menggunakan Vim dalam mode Ex:
\v
nyalakan sihir.{6}
temukan garis dengan 6 karakter atau lebihv
pilihan sebaliknyad
menghapusx
Simpan dan tutupsumber
Solusi Ruby:
Ide sederhana: redirect file ke stdin ruby, dan cetak baris dari stdin hanya jika panjangnya lebih besar atau sama dengan 6
sumber