Yeni dosya içeren dizeyi büyük dosyada değiştir


16

Herkes arama / dizeleri biraz bellek tasarruflu bir şekilde "ikili" için satır tabanlı olmayan bir araç biliyor mu? Bu soruya da bakın .

Ben bunun gibi görünüyor benzer işlemek istiyorum bir + 2GB metin dosyası var:

sed -e 's/>\n/>/g'

Bu, a'dan sonra meydana gelen >ancak başka bir yerde olmayan tüm yeni satırları kaldırmak istediğim için , bu da dışarıda tr -d.

Bu komut ( benzer bir sorunun cevabından aldım ) ile başarısız olur couldn't re-allocate memory:

sed --unbuffered ':a;N;$!ba;s/>\n/>/g'

Peki, C'ye başvurmadan başka yöntemler var mı? Perl'den nefret ediyorum, ama bu durumda bir istisna yapmaya hazırım :-)

Veride oluşmayan herhangi bir karakterden emin değilim, bu yüzden geçici \nolarak başka bir karakterle değiştirmek mümkünse kaçınmak istediğim bir şey.

İyi fikirleriniz var mı?


Seçeneği denedin --unbufferedmi?
ctrl-alt-delor

--unbufferedBellek ile veya bellek
yetersiz

Ne yapar $!?
ctrl-alt-delor

İlk sed komutunda sorun nedir. İkincisi, her şeyi desen alanına okuyor gibi gözüküyor, bunun olduğunu bilmiyorum $!. Ben bekliyoruz Bu gerekecektir ÇOK bellek.
ctrl-alt-delor

Sorun sed'in her şeyi satır olarak okumasıdır, bu yüzden ilk komut satır satırlarını yeniden çıkardığı için satırları kaldırmaz. İkinci komut sadece bir çözümdür. sedBu durumda uygun bir araç olmadığını düşünüyorum .
MattBianco

Yanıtlar:


14

Bu gerçekten Perl'de önemsiz, nefret etmemelisin!

perl -i.bak -pe 's/>\n/>/' file

açıklama

  • -i: dosyayı yerinde düzenleyin ve çağrılan orijinalin bir yedeğini oluşturun file.bak. Yedek istemiyorsanız perl -i -pebunun yerine kullanın.
  • -pe: giriş dosyasını satır satır okuyun ve verilen komut dosyasını uyguladıktan sonra her satırı yazdırın -e.
  • s/>\n/>/: oyuncu değişikliği gibi sed.

Ve işte bir awkyaklaşım:

awk  '{if(/>$/){printf "%s",$0}else{print}}' file2 

3
+1. awk golf:awk '{ORS=/>$/?"":"\n"}1'
glenn jackman

1
Neden perl'i genel olarak sevmiyorum, bu cevabı (veya aslında Gnouc'un cevabına yaptığınız yorumu) seçmemizin aynı nedeni: okunabilirlik. Basit bir "sed paterni" ile perl -pe kullanmak karmaşık bir sed-ifadesinden çok daha okunabilir.
MattBianco

3
@MattBianco yeterince adil ama biliyorsunuz ki Perl ile ilgisi yok. Gnouc'un kullandığı bakış açısı, Perl'in hatası değil, bazı düzenli ifade dillerinin (PCRE'ler dahil ancak bunlarla sınırlı olmamak üzere) bir özelliğidir. Ayrıca, ':a;N;$!ba;s/>\n/>/g'sorunuzdaki bu aşırı canavarlığı sunduktan sonra, okunabilirlikten şikayet etme hakkınızdan feragat ettiniz! : P
terdon

@glennjackman güzel! Yapıyla oynuyordum foo ? bar : bazama çalışamadım.
terdon

@terdon: Evet, benim hatam. Silin.
cuonglm

7

Bir perlçözüm:

$ perl -pe 's/(?<=>)\n//'

Açıklama

  • s/// dize ikamesi için kullanılır.
  • (?<=>) göz kamaştırıcı kalıptır.
  • \n satırsonu ile eşleşir.

Tüm desen, ondan >önceki tüm yeni satırın kaldırılması anlamına gelir.


2
programın bölümlerinin ne yaptığını yorumlamak ister misiniz? Hep öğrenmek isterim.
MattBianco

2
Neden gözbebeği ile uğraşasınız ki? Neden sadece s/>\n/>/?
terdon

1
ya s/>\K\n//da işe yarayacak
glenn jackman

@terdon: Sadece ilk şey, yerine yerine kaldırmak
cuonglm

@glennjackman: iyi nokta!
cuonglm

3

Buna ne dersin:

sed ':loop
  />$/ { N
    s/\n//
    b loop
  }' file

GNU sed için, soruya göre -u( --unbuffered) seçeneğini eklemeyi de deneyebilirsiniz . GNU sed ayrıca basit bir tek katlı olarak bundan memnun:

sed ':loop />$/ { N; s/\n//; b loop }' file

\nDosya biterse sonuncusu kaldırılmaz >\n, ancak yine de tercih edilebilir.
Stéphane Chazelas

@ StéphaneChazelas, kapanışın neden }ayrı bir ifadede olması gerekiyor? bu çok satırlı bir ifade olarak çalışmaz mı?
Graeme

1
Yani birlikte POSIX tayfsal enerji çalışacak b loop\n}veya -e 'b loop' -e '}'değil olarak b loop;}değil kesinlikle ve b loop}çünkü }ve ;etiket adlarına geçerlidir (aklı başında kimse kullanmak istiyorsunuz ama. Ve GNU sed anlama geldiğini POSIX uyumlu değil) ve }ayrılacak için komut ihtiyaçları dan bkomuta.
Stéphane Chazelas

@ StéphaneChazelas, GNU sed, yukarıdakilerin hepsinden bile memnun --posix! Standart ayraç ifadeleri için aşağıdakilere de sahiptir - The list of sed functions shall be surrounded by braces and separated by <newline>s. Bu, noktalı virgüllerin yalnızca diş telleri dışında kullanılması gerektiği anlamına gelmiyor mu?
Graeme

mikeserv, döngü ile biten ardışık satırları işlemek için gereklidir >. Orijinalin hiç bir tane yoktu, bu Stéphane tarafından işaret edildi.
Graeme

1

Kullanılacak gerekir sedile Nkomuta, ama hile desen uzaydan size (başka eklediğiniz her seferinde bir satır silmek olacak böylece model uzay yerine her zaman bütün içinde okumaya çalışmak, sadece 2 ardışık satırları içerdiğini dosyası) - deneyin

sed ':a;$!N;s/>\n/>/;P;D;ba'

DÜZENLEME: Peteris Krumins'in Ünlü Sed One- Liners'ı yeniden okuduktan sonra daha iyi bir sedçözüm olacağına inanıyorum

sed -e :a -e '/>$/N; s/\n//; ta'

Bu, yalnızca >sonunda bir eşleşme yapılması durumunda aşağıdaki satırı ekler ve arka arkaya eşleşen satırların durumunu ele almak için koşullu olarak geri dönmelidir (Krumin'in 39'udur . Bir ters eğik çizgi ile bitiyorsa bir sonrakine bir satır ekleyin. "\" tam olarak ikame haricinde >için \karakter katılmak gibi, ve benzeri) karakter çıkışı tutulur birleştirme olması.


2
2 ardışık satır biterse >(bu da
GNU'ya

1

sedson satırsonu olmadan çıktı yaymanın bir yolunu sunmaz. NTemel olarak işe yarar yaklaşımınız çalışır, ancak eksik satırları bellekte depolar ve bu nedenle satırlar çok uzun olursa başarısız olabilir (sed implentasyonları genellikle çok uzun satırları işlemek için tasarlanmamıştır).

Bunun yerine awk kullanabilirsiniz.

awk '{if (/<$/) printf "%s", $0; else print}'

Alternatif bir yaklaşım, tryeni satır karakterini sıkıcı, sık görülen bir karakterle değiştirmek için kullanmaktır . Alan burada işe yarayabilir - verilerinizdeki her satırda veya en azından büyük miktarda satırda görünme eğilimi gösteren bir karakter seçin.

tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n'

Her iki yöntem de burada diğer cevaplarda daha iyi etki gösterdiği gösterilmiştir. Ve onun yaklaşımı sed2.5 gigabayt tampon olmadan işe yaramıyor.
mikeserv

Herhangi biri awk'den bahsetti mi? Oh, kaçırdım, sadece bir sebepten ötürü terdon'un cevabında perl fark ettim. Kimse bu tryaklaşımdan bahsetmedi - mikeserv, kullandığınız farklı (geçerli, ancak daha az genel) bir yaklaşım yayınladınız tr.
Gilles 'SO- kötü olmayı kes

geçerli, ancak daha az genel sesler bana sizin gibi çalışan, hedefli bir çözüm olarak adlandırdı. 0 upvotes olduğundan garip olan böyle bir şey yararlı olmadığını iddia etmek zor olduğunu düşünüyorum . Kendi çözümüm ve daha genel teklifiniz arasında görebildiğim en büyük fark , benimki özellikle bir problemi çözerken, sizinki genel olarak sizin olabilir. Bu değerli olabilir - ve oyumu bile tersine çevirebilirim - ama aynı zamanda aralarındaki 7 saatin sinir bozucu meselesi ve diğerlerini taklit eden cevaplarınızın tekrar eden teması da var. Bunu açıklayabilir misin?
mikeserv



-1

Bunu yapmanın birçok yolu var ve çoğu burada gerçekten çok iyi, ama bence bu benim favorim:

tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'

Ya da:

tr '>\n' '\n>' | sed 's/^>*//' | tr '\n>' '>\n'

İlk cevabını hiç işe alamıyorum. İkincisinin zarafetine hayran kalırken, kaldırmanız gerektiğine inanıyorum *. Şimdi olduğu gibi, a ile biten bir satırı izleyen boş satırları siler >. … Hmm. Soruya baktığımda, bunun biraz belirsiz olduğunu görüyorum. Soru “A'dan sonra meydana gelen tüm yeni satırları kaldırmak istiyorum >…” diyor. Bunun, >\n\n\n\n\nfoodeğiştirilmesi gerektiği anlamına geldiğini düşünüyorum \n\n\n\nfoo, ancak sanırım fooistenen çıktı olabilir.
Scott

@Scott - Aşağıdakilerle ilgili varyasyonlarla test ettim: printf '>\n>\n\n>>\n>\n>>>\n>\nf\n\nff\n>\n' | tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'- bu >>>>>>>>>>f\n\nff\n\nbenim için ilk cevapla sonuçlanır . Yine de kırmak için ne yaptığınızı merak ediyorum, çünkü düzeltmek istiyorum. İkinci noktaya gelince - bunun belirsiz olduğu konusunda hemfikir değilim. OP kaldırmak için sormuyor tüm > önceki bir \newline, ancak bunun yerine kaldırmak için tüm \n ewlines aşağıdaki bir >.
mikeserv

1
Evet, ancak geçerli bir yorumda >\n\n\n\n\n, sadece ilk satırsonu bir >; diğerleri diğer yeni satırları takip ediyor. OP'nin “sadece işe yaradıysa istediğim şey bu” önerisinin sed -e 's/>\n/>/g'değil, olduğuna dikkat edin sed -e 's/>\n*/>/g'.
Scott

1
@Scott - öneri işe yaramadı ve asla işe yaramadı. Kodu tam olarak anlamayan birinin kod önerisinin, kişinin kullandığı düz dil olarak geçerli bir yorumlama noktası olarak kabul edilebileceğine inanmıyorum. Ve ayrıca, çıkış - aslında çalışıp çalışmadığını - ait s/>\n/>/üzerinde >\n\n\n\n\nhala o şey olurdu s/>\n/>/misiniz düzenlemek.
mikeserv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.