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 file1
yukarı çizgiler içerir XYZ
ve 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 file1
yukarı çizgiler içerir XYZ
ve satırların dinlenme file2
.
Yanıtlar:
İle awk
yapabilirsiniz:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
Açıklama: İlk awk
bağı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 . awk
Program değişkeni tarafından belirtilen dosyaya tüm satırları yazdırır out
( {print >out}
). Kalıp XYZ
bulunursa, çı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 s
ilently öncesi ile parçalar yaratma, dosya bölmek f
ix file
ve n
örneğin bir tek basamaklı kullanılarak umbered file0
vb 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 regex
için bir +1
uzaklık ekleyin :
csplit -sf file -n 1 large_file /XYZ/+1
Bu iki dosya oluşturur file0
ve file1
. Gerçekten ihtiyaç duyduğunuzda ise ismini vermek file1
ve file2
her zaman boş bir desen ekleyebilirsiniz csplit
komuta ve ilk dosyayı kaldırın:
csplit -sf file -n 1 large_file // /XYZ/+1
yaratır file0
, file1
ve file2
ancak file0
güvenle kaldırabilirsiniz böylece boş:
rm -f file0
Bir modern ile yukarıdaki temel cevaplardan birinin ksh
kabuk varyantı (yani olmadan sed
) sed
:
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
Ve ksh
tek 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
/ cat
tabanlı yaklaşımla 39-47 saniyeye kıyasla 19-21 saniye gerekiyordu ).
read
ve print
- sadece kendi çıktısını almasına izin vermelisin. AST araç setini tamamen oluşturursanız ve tüm ksh
yerleşik yapıları derlerseniz performans daha iyi olur - sed
aslında bunlardan biri olmayan benim için garip . Ama while <file do
sanırım benim gibi şeylerle sed
çok fazla ihtiyacın yok ...
awk
karşılaştırmalı değerlendirmeniz nasıl oldu ? Ve ksh
muhtemelen bu dövüşü her zaman kazanacağından eminim , eğer bir GNU kullanıyorsanız sed
, çok adil değilsiniz sed
- GNU'nun -u
nbuffered'ı, 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 sed
yapmanı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 while
yavaş olmasını beklediğim açık bir döngü (ancak kontrol edilmedi).
head
yerine 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 f
ve iki çıkış dosyaları f1
ve 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>f2
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:
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
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
XYZ
hat çıkışında veya olmasın dahil edilecek?