Adakah yang tahu alat berbasis-non-baris untuk "biner" mencari / mengganti string dengan cara yang agak hemat memori? Lihat pertanyaan ini juga.
Saya memiliki file teks + 2GB yang ingin saya proses serupa dengan apa yang tampaknya dilakukan:
sed -e 's/>\n/>/g'
Itu berarti, saya ingin menghapus semua baris baru yang terjadi setelah >
, tetapi tidak di tempat lain, sehingga mengesampingkan tr -d
.
Perintah ini (yang saya dapatkan dari jawaban pertanyaan serupa ) gagal dengan couldn't re-allocate memory
:
sed --unbuffered ':a;N;$!ba;s/>\n/>/g'
Jadi, apakah ada metode lain tanpa menggunakan C? Saya benci perl, tetapi saya bersedia membuat pengecualian dalam kasus ini :-)
Saya tidak tahu pasti karakter apa pun yang tidak muncul dalam data, jadi mengganti sementara \n
dengan karakter lain adalah sesuatu yang ingin saya hindari jika memungkinkan.
Ada ide bagus, siapa saja?
sumber
--unbuffered
?--unbuffered
kehabisan memori$!
harus dilakukan$!
itu benar. Ini saya berharap akan membutuhkan BANYAK memori.sed
bukan alat yang tepat dalam hal ini.Jawaban:
Ini benar-benar sepele di Perl, Anda tidak harus membencinya!
Penjelasan
-i
: edit file di tempat, dan buat cadangan dari aslinya yang disebutfile.bak
. Jika Anda tidak ingin cadangan, gunakanperl -i -pe
saja.-pe
: baca file input baris demi baris dan cetak setiap baris setelah menerapkan skrip yang diberikan sebagai-e
.s/>\n/>/
: substitusi, sama sepertised
.Dan inilah
awk
pendekatannya:sumber
awk '{ORS=/>$/?"":"\n"}1'
':a;N;$!ba;s/>\n/>/g'
dalam pertanyaan Anda, Anda melepaskan hak Anda untuk mengeluh tentang keterbacaan! : Pfoo ? bar : baz
konstruk tetapi tidak bisa membuatnya bekerja.Sebuah
perl
solusi:Penjelasan
s///
digunakan untuk substitusi string.(?<=>)
adalah pola lookbehind.\n
cocok dengan baris baru.Seluruh makna pola menghapus semua baris baru yang ada
>
sebelumnya.sumber
s/>\n/>/
?s/>\K\n//
akan juga berfungsiBagaimana dengan ini:
Untuk GNU, Anda juga dapat mencoba menambahkan opsi
-u
(--unbuffered
) sesuai pertanyaan. GNU sed juga senang dengan ini sebagai one-liner sederhana:sumber
\n
jika file berakhir>\n
, tapi itu mungkin lebih baik.}
harus dalam ekspresi yang terpisah? Apakah ini tidak akan berfungsi sebagai ekspresi multiline?b loop\n}
atau-e 'b loop' -e '}'
tetapi tidakb loop;}
dan tentu saja tidakb loop}
karena}
dan;
valid dalam nama label (meskipun tidak ada orang waras yang akan menggunakannya. Dan itu berarti sed GNU tidak sesuai POSIX) dan}
perintah perlu dipisahkan darib
perintah.sed
senang dengan semua hal di atas bahkan dengan--posix
! Standar ini juga memiliki yang berikut untuk ekspresi penyangga -The list of sed functions shall be surrounded by braces and separated by <newline>s
. Apakah ini tidak berarti bahwa titik koma hanya boleh digunakan di luar kawat gigi?>
. Asli tidak pernah punya, ini ditunjukkan oleh Stéphane.Anda harus dapat menggunakan
sed
denganN
perintah, tetapi triknya adalah menghapus satu baris dari ruang pola setiap kali Anda menambahkan yang lain (sehingga ruang pola selalu hanya berisi 2 baris berturut-turut, alih-alih mencoba membaca secara keseluruhan file) - cobaSUNTING : setelah membaca ulang Sed Sederet Liners Terkenal Peteris Krumins Dijelaskan Saya percaya
sed
solusi yang lebih baik adalahyang hanya menambahkan baris berikut dalam kasus bahwa itu sudah membuat
>
kecocokan di akhir, dan harus kembali secara kondisional untuk menangani kasus pencocokan garis berturut-turut (itu adalah Krumin 39. Tambahkan baris ke yang berikutnya jika berakhir dengan backslash "\" tepatnya kecuali untuk substitusi>
untuk\
sebagai karakter bergabung, dan fakta bahwa karakter gabungan dipertahankan dalam output).sumber
>
(itu juga spesifik untuk GNU)sed
tidak menyediakan cara untuk memancarkan output tanpa baris baru final. Pendekatan Anda menggunakan secaraN
fundamental berfungsi, tetapi menyimpan garis yang tidak lengkap dalam memori, dan dengan demikian dapat gagal jika garis menjadi terlalu panjang (implementasi sed tidak biasanya dirancang untuk menangani garis yang sangat panjang).Anda bisa menggunakan awk saja.
Pendekatan alternatif digunakan
tr
untuk menukar karakter baris baru dengan karakter "membosankan", yang sering terjadi. Spasi mungkin berfungsi di sini - pilih karakter yang cenderung muncul di setiap baris atau setidaknya sebagian besar garis dalam data Anda.sumber
sed
tidak bekerja tanpa buffer 2,5 gigabyte.tr
pendekatan - mikeserv, Anda memposting pendekatan yang berbeda (valid, tetapi kurang umum) yang kebetulan juga digunakantr
.bagaimana dengan menggunakan ed?
(via http://wiki.bash-hackers.org/howto/edit-ed )
sumber
Saya akhirnya menggunakan gsar seperti yang dijelaskan dalam jawaban ini seperti ini:
sumber
Ada banyak cara untuk melakukan ini, dan sebagian besar di sini benar-benar bagus, tetapi saya pikir ini yang menjadi favorit saya:
Atau bahkan:
sumber
*
. Caranya sekarang, itu akan menghapus setiap baris kosong mengikuti garis yang diakhiri dengan a>
. ... Hmm. Melihat kembali pertanyaan itu, saya melihat bahwa itu agak ambigu. Pertanyaannya mengatakan, "Saya ingin menghapus semua baris baru yang terjadi setelah>
, ..." Saya menafsirkan itu berarti yang>\n\n\n\n\nfoo
harus diubah\n\n\n\nfoo
, tetapi saya kirafoo
mungkin hasil yang diinginkan.printf '>\n>\n\n>>\n>\n>>>\n>\nf\n\nff\n>\n' | tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'
- yang menghasilkan>>>>>>>>>>f\n\nff\n\n
bagi saya dengan jawaban pertama. Saya ingin tahu apa yang Anda lakukan untuk memecahkannya, karena saya ingin memperbaikinya. Adapun poin kedua - Saya tidak setuju bahwa itu ambigu. OP tidak meminta untuk menghapus semua>
sebelumnya yang\n
ewline, melainkan untuk menghapus semua\n
ewlines berikut a>
.>\n\n\n\n\n
, hanya baris baru pertama setelah a>
; semua yang lain mengikuti baris baru lainnya. Perhatikan bahwa saran OP "ini adalah yang saya inginkan, kalau saja itu berhasil"sed -e 's/>\n/>/g'
, bukansed -e 's/>\n*/>/g'
.s/>\n/>/
pada>\n\n\n\n\n
masih akan menjadi sesuatu yangs/>\n/>/
akan diedit.