Baru-baru ini saya mengajukan pertanyaan tentang cara menghapus karakter baris baru jika itu terjadi setelah karakter tertentu lainnya.
Alat pemrosesan teks Unix sangat kuat, tetapi hampir semuanya berhubungan dengan baris teks, yang sebagian besar baik-baik saja ketika input sesuai dengan memori yang tersedia.
Tetapi apa yang harus saya lakukan jika saya ingin mengganti urutan teks dalam file besar yang tidak mengandung baris baru?
Misalnya ganti <foobar>
dengan \n<foobar>
tanpa membaca input baris demi baris? (Karena hanya ada satu baris dan panjangnya 2.5G karakter).
text-processing
MattBianco
sumber
sumber
perl
ataupython
?gsar
( home.online.no/~tjaberg ) yang akan saya coba.Jawaban:
Hal pertama yang terjadi pada saya ketika menghadapi masalah jenis ini adalah mengubah pemisah catatan. Di sebagian besar alat, ini diatur
\n
secara default tetapi itu bisa diubah. Sebagai contoh:Perl
Penjelasan
-0
: ini mengatur pemisah rekaman input ke karakter yang diberi nilai heksadesimalnya . Dalam hal ini, saya mengaturnya ke>
nilai hex yang mana3E
. Format umum adalah-0xHEX_VALUE
. Ini hanya trik untuk memecah garis menjadi potongan-potongan yang bisa dikelola.-pe
: cetak setiap baris input setelah menerapkan skrip yang diberikan oleh-e
.s/<foobar>/\n$&/
: substitusi sederhana. Apa$&
pun yang cocok, dalam hal ini<foobar>
.awk
Penjelasan
RS="<"
: atur pemisah rekaman input ke>
.gsub(/foobar>/,"\n<foobar>")
: gantikan semua kasusfoobar>
dengan\n<foobar>
. Perhatikan bahwa karenaRS
telah diatur ke<
, semua<
dihapus dari file input (begitulah caraawk
kerjanya) sehingga kami harus mencocokkanfoobar>
(tanpa a<
) dan menggantinya dengan\n<foobar>
.printf "%s",$0
: cetak "garis" saat ini setelah substitusi.$0
adalah catatan saat iniawk
sehingga akan menampung apa pun sebelum<
.Saya mengujinya pada 2,3 GB, file baris tunggal yang dibuat dengan perintah ini:
Baik
awk
danperl
jumlah diabaikan digunakan memori.sumber
Tie::File
perldoc.perl.org/Tie/File.html . Saya pikir itu fitur terbaikPerl
ketika berhadapan dengan file besar.Tie::File
merupakan modul inti sejak ituv5.7.3
.gsar (pencarian umum dan ganti) adalah alat yang sangat berguna untuk tujuan ini.
Sebagian besar jawaban untuk pertanyaan ini menggunakan alat berbasis catatan dan berbagai trik untuk membuatnya beradaptasi dengan masalah, seperti mengalihkan karakter pemisah rekaman default ke sesuatu yang dianggap cukup sering terjadi pada input sehingga tidak membuat setiap rekaman terlalu besar untuk ditangani.
Dalam banyak kasus ini sangat bagus dan bahkan dapat dibaca. Saya lakukan seperti masalah yang dapat dengan mudah / efisien diselesaikan dengan alat di mana-mana-tersedia seperti
awk
,tr
,sed
dan shell Bourne.Melakukan pencarian biner dan mengganti dalam file besar sembarang dengan konten acak tidak cocok untuk alat unix standar ini.
Beberapa dari Anda mungkin berpikir ini curang, tetapi saya tidak melihat bagaimana menggunakan alat yang tepat untuk pekerjaan itu bisa salah. Dalam hal ini adalah program C yang disebut
gsar
dilisensikan di bawah GPL v2 , jadi saya sedikit terkejut bahwa tidak ada paket untuk alat yang sangat berguna ini di gentoo , redhat , atau ubuntu .gsar
menggunakan varian biner dari algoritma pencarian string Boyer-Moore .Penggunaan mudah:
di mana
-F
berarti mode "filter", yaitu bacastdin
tulisstdout
. Ada metode untuk beroperasi pada file juga.-s
menentukan string pencarian dan-r
penggantinya. Notasi titik dua dapat digunakan untuk menentukan nilai byte sewenang-wenang.Mode case-insensitive didukung (
-i
), tetapi tidak ada dukungan untuk ekspresi reguler, karena algoritma menggunakan panjang string pencarian untuk mengoptimalkan pencarian.Alat ini juga dapat digunakan hanya untuk pencarian, sedikit mirip
grep
.gsar -b
menampilkan byte byte dari string pencarian yang cocok, dangsar -l
mencetak nama file dan jumlah kecocokan jika ada, sedikit seperti digabungkangrep -l
denganwc
.Alat ini ditulis oleh Tormod Tjaberg (awal) dan Hans Peter Verne (perbaikan).
sumber
gsar
.Dalam kasus sempit di mana string target dan penggantian memiliki panjang yang sama, pemetaan memori dapat dilakukan untuk menyelamatkan. Ini sangat berguna jika penggantian harus dilakukan di tempat. Anda pada dasarnya memetakan file ke dalam memori virtual proses, dan ruang alamat untuk pengalamatan 64-bit sangat besar. Perhatikan bahwa file tersebut tidak harus dipetakan ke memori fisik sekaligus , sehingga file yang beberapa kali ukuran memori fisik yang tersedia pada mesin dapat ditangani.
Berikut adalah contoh Python yang menggantikan
foobar
denganXXXXXX
sumber
Ada banyak alat untuk ini:
dd
adalah apa yang ingin Anda gunakan jika Anda ingin memblokir file - andal hanya baca sejumlah byte saja beberapa kali saja. Ini dengan mudah menangani memblokir dan membuka blokir aliran file:tr -dc '[:graph:]' </dev/urandom | dd bs=32 count=1 cbs=8 conv=unblock,sync 2>/dev/null
UI(#Q5\e BKX2?A:Z RAxGm:qv t!;/v!)N
Saya juga menggunakan di
tr
atas karena dapat menangani konversi byte ASCII ke yang lain (atau, dalam hal ini, menghapus byte ASCII yang bukan karakter yang dapat dicetak tanpa spasi). Itulah yang saya gunakan untuk menjawab pertanyaan Anda yang lain pagi ini, pada kenyataannya, ketika saya melakukannya:Ada banyak yang mirip . Daftar itu harus menyediakan subset common-denominator terendah yang dengannya Anda mungkin terbiasa.
Tapi, jika saya akan melakukan pemrosesan teks pada file biner 2.5gbs, saya mungkin mulai dengan
od
. Ini dapat memberi Andaoctal dump
atau salah satu dari beberapa format lainnya. Anda dapat menentukan semua jenis opsi - tetapi saya hanya akan melakukan satu byte per baris dalam\C
format yang diloloskan:Data yang akan Anda dapatkan
od
akan teratur pada interval apa pun yang Anda tentukan - seperti yang saya tunjukkan di bawah ini. Tapi pertama-tama - inilah jawaban untuk pertanyaan Anda:Itu sedikit di atas
\n
batas pada garis,\0
nol,\t
abs dan<spaces>
sambil mempertahankan\C
string yang lolos untuk pembatas. PerhatikanH
danx
fungsi yang digunakan - setiap kalised
bertemu pembatas itu menukar isi buffer memorinya. Dengan cara inised
hanya menyimpan informasi sebanyak yang diperlukan untuk membatasi file secara andal dan tidak menyerah pada buffer overruns - tidak, yaitu, asalkan itu benar-benar bertemu dengan pembatasnya. Selama itu terjadi,sed
akan terus memproses inputnya danod
akan terus menyediakannya sampai bertemuEOF
.Seperti apa, outputnya terlihat seperti ini:
Jadi jika saya mau
foobar
:Sekarang jika Anda ingin menggunakan
C
pelarian itu cukup mudah - karena backslashsed
sudah berlipat ganda\\
lolos dari semua backslash input tunggal, jadiprintf
dari yangxargs
sudah ada tidak akan ada masalah menghasilkan output dengan spesifikasi Anda. Tetapixargs
makanlah kutipan shell sehingga Anda harus menggandakan penawaran itu lagi:Itu bisa dengan mudah disimpan ke variabel shell dan output nanti dengan cara yang sama. Yang terakhir
sed
menyisipkan\
garis miring terbalik sebelum setiap karakter dalam inputnya, dan itu saja.Dan inilah yang terlihat seperti sebelumnya
sed
:sumber
Awk beroperasi pada catatan yang berurutan. Ia dapat menggunakan karakter apa saja sebagai pemisah rekaman (kecuali byte nol pada banyak implementasi). Beberapa implementasi mendukung ekspresi reguler sewenang-wenang (tidak cocok dengan string kosong) sebagai pemisah rekaman, tetapi ini bisa sangat sulit karena pemisah rekaman dipotong dari akhir setiap rekaman sebelum dimasukkan ke dalam
$0
(AWK GNU menetapkan variabelRT
ke pemisah rekaman) yang dilucuti dari akhir catatan saat ini). Catatan yangprint
mengakhiri outputnya dengan pemisah catatan keluaranORS
yang merupakan baris baru secara default dan ditetapkan secara independen dari pemisah catatan inputRS
.Anda dapat secara efektif memilih karakter yang berbeda sebagai pemisah record alat bantu lainnya (
sort
,sed
, ...) dengan menukar baris baru dengan karakter dengantr
.Banyak utilitas teks GNU mendukung penggunaan byte nol alih-alih baris baru sebagai pemisah.
sumber