dosyayı bir desende iki parçaya böl


14

Büyük bir dosyayı bir desende iki parçaya nasıl bölebilirim?

Bir örnek verelim file.txt:

ABC
EFG
XYZ
HIJ
KNL

Ben bu dosyayı bölmek istediğiniz XYZşekilde file1yukarı çizgiler içerir XYZve satırların dinlenme file2.


Meli XYZhat çıkışında veya olmasın dahil edilecek?
terdon

@terdon Benim durumumda "XYZ" satırı dosya2'nin parçası olmamalıdır. Ancak bunu yapmanın bir yolu varsa, lütfen cevabı ekleyin. Diğer bazı durumlarda yararlı olabilir.
d.putto

Yeterince adil, bitti.
terdon

Yanıtlar:


10

İle awkyapabilirsiniz:

awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile


Açıklama: İlk awkbağımsız değişken ( out=file1), sonraki bağımsız değişken ( largefile) işlenirken çıktı için kullanılacak dosya adına sahip bir değişken tanımlar . awkProgram değişkeni tarafından belirtilen dosyaya tüm satırları yazdırır out( {print >out}). Kalıp XYZbulunursa, çıktı değişkeni {out="file2}", sonraki veri satırlarını yazdırmak için hedef olarak kullanılacak yeni dosyayı ( ) işaret edecek şekilde yeniden tanımlanır .

Referanslar:


14

Bu bir iş csplit:

csplit -sf file -n 1 large_file /XYZ/

olur silently öncesi ile parçalar yaratma, dosya bölmek fix fileve nörneğin bir tek basamaklı kullanılarak umbered file0vb kullanarak o Not /regex/maçları o satır dahil kadar bölmek değil regex. Satır eşleşmesine bölmek ve dahil etmek regexiçin bir +1uzaklık ekleyin :

csplit -sf file -n 1 large_file /XYZ/+1

Bu iki dosya oluşturur file0ve file1. Gerçekten ihtiyaç duyduğunuzda ise ismini vermek file1ve file2her zaman boş bir desen ekleyebilirsiniz csplitkomuta ve ilk dosyayı kaldırın:

csplit -sf file -n 1 large_file // /XYZ/+1

yaratır file0, file1ve file2ancak file0güvenle kaldırabilirsiniz böylece boş:

rm -f file0

Bence bu en basit cevap. Tek yapmanız gereken bazı desenleri listelemek ve dosya sırayla onlara göre bölünecektir. Parlak!
Henry Blyth

6

Bir modern ile yukarıdaki temel cevaplardan birinin kshkabuk varyantı (yani olmadan sed) sed:

{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1


Ve kshtek başına başka bir varyant (yani ayrıca atlamak cat):

{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1


(Saf kshçözüm oldukça performanslı görünüyor; 2.4 GB test dosyasında sed/ cattabanlı yaklaşımla 39-47 saniyeye kıyasla 19-21 saniye gerekiyordu ).


Bu var çok hızlı. Ama ihtiyacın olduğunu sanmıyorum readve print- sadece kendi çıktısını almasına izin vermelisin. AST araç setini tamamen oluşturursanız ve tüm kshyerleşik yapıları derlerseniz performans daha iyi olur - sedaslında bunlardan biri olmayan benim için garip . Ama while <file dosanırım benim gibi şeylerle sedçok fazla ihtiyacın yok ...
mikeserv

Yine de merak ediyorum - awkkarşılaştırmalı değerlendirmeniz nasıl oldu ? Ve kshmuhtemelen bu dövüşü her zaman kazanacağından eminim , eğer bir GNU kullanıyorsanız sed, çok adil değilsiniz sed- GNU'nun -unbuffered'ı, tanımlayıcının ofsetinin programın bırakıldığı yerde bırakılmasını sağlamak için POissly fakir bir yaklaşımdır. - programın düzenli çalışmasını yavaşlatmaya gerek yoktur - tamponlama iyidir - tüm sedyapmanız gereken, bitirildiğinde tanımlayıcıyı lseek etmektir. Hangi nedenle olursa olsun GNU bu zihniyeti tersine çevirir.
mikeserv

@mikeserv; Yeniden yönlendirme modeli eşleşmesi, desen bulunana kadar yapılır ve açıkça gösterildiği gibi yapılmazsa bulunan desene sahip çizgi yazdırılmaz. (En azından bu benim testimi gösterdi.) Hayır while; yazdırma dolaylı olarak <##yönlendirme operatörünün tanımlanmış yan etkisi olarak yapılır . Ve sadece eşleşen çizginin yazdırılması gerekir. (Bu şekilde kabuk özelliği uygulaması incl./excl desteği için en esnektir.) Belirgin bir şekilde whileyavaş olmasını beklediğim açık bir döngü (ancak kontrol edilmedi).
Janis

1
@mikeserv; Ah tamam. BTW headyerine sadece denedim read; sadece biraz daha yavaş görünüyor, ama en terser kodu: { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3.
Janis

1
@mikeserv; İyi bir nokta; değildi. Ama yerleşik olanı etkinleştirdiğimde (sadece bitirdim ve sonuçları kontrol ettim) garip bir şekilde aynı sayılar. (Belki okumaya kıyasla bazı fonksiyon çağrısı tepegöz?)
Janis

6
{ sed '/XYZ/q' >file1; cat >file2; } <infile

GNU ile nbuffered anahtarını sedkullanmalısınız -u. Çoğu diğer sedsadece çalışmalıdır.

XYZ'yi dışarıda bırakmak için ...

{ sed -n '/XYZ/q;p'; cat >file2; } <infile >file1

3

Bunu GNU sed ile deneyin:

sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file

Kısa:sed -e '1,/XYZ/{w file1' -e 'd}' large_file > file2
don_crissti

1

Kolay bir saldırı, hedef desenin eşleşip eşleşmediğine bağlı olarak STDOUT veya STDERR'a yazdırmaktır. Daha sonra çıktıyı buna göre yönlendirmek için kabuğun yeniden yönlendirme işleçlerini kullanabilirsiniz. Örneğin, Perl, giriş dosyasını varsayarak denir fve iki çıkış dosyaları f1ve f2:

  1. Bölünmüş kalıpla eşleşen satırı atmak:

    perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
  2. Eşleşen hat dahil:

    perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2

Alternatif olarak, farklı dosya tanıtıcılarına yazdırın:

  1. Bölünmüş kalıpla eşleşen satırı atmak:

    perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
    if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
  2. Eşleşen hat dahil:

    perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
              $a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
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.