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.
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.
Yanıtlar:
İ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:
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
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 ).
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 ...
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.
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).
headyerine sadece denedim read; sadece biraz daha yavaş görünüyor, ama en terser kodu: { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3.
Bunu GNU sed ile deneyin:
sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file
sed -e '1,/XYZ/{w file1' -e 'd}' large_file > file2
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:
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>f2Eşleşen hat dahil:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2Alternatif olarak, farklı dosya tanıtıcılarına yazdırın:
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 "$_";' fEşleşen hat dahil:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZhat çıkışında veya olmasın dahil edilecek?