จะแบ่งไฟล์ขนาดใหญ่ออกเป็นสองส่วนได้อย่างไรในรูปแบบ
รับตัวอย่างfile.txt:
ABC
EFG
XYZ
HIJ
KNL
ฉันต้องการที่จะแยกไฟล์นี้ที่XYZดังกล่าวว่าfile1มีเส้นขึ้นไปและส่วนที่เหลือของสายในXYZfile2
จะแบ่งไฟล์ขนาดใหญ่ออกเป็นสองส่วนได้อย่างไรในรูปแบบ
รับตัวอย่างfile.txt:
ABC
EFG
XYZ
HIJ
KNL
ฉันต้องการที่จะแยกไฟล์นี้ที่XYZดังกล่าวว่าfile1มีเส้นขึ้นไปและส่วนที่เหลือของสายในXYZfile2
คำตอบ:
ด้วยawkคุณสามารถทำได้:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
คำอธิบาย:awkอาร์กิวเมนต์แรก( out=file1) กำหนดตัวแปรที่มีชื่อไฟล์ที่จะใช้สำหรับการส่งออกในขณะที่การlargefileประมวลผลอาร์กิวเมนต์ที่ตามมา ( ) awkโปรแกรมจะพิมพ์ทุกสายไปยังแฟ้มที่ระบุโดยตัวแปรout( {print >out}) หากพบรูปแบบXYZตัวแปรเอาต์พุตจะถูกกำหนดใหม่ให้ชี้ไปที่ไฟล์ใหม่ ( {out="file2}") ซึ่งจะใช้เป็นเป้าหมายในการพิมพ์บรรทัดข้อมูลที่ตามมา
อ้างอิง:
นี่คืองานสำหรับcsplit:
csplit -sf file -n 1 large_file /XYZ/
จะsilently แยกไฟล์, การสร้างชิ้นก่อนfix fileและnumbered ใช้หลักเดียวเช่นfile0ฯลฯ หมายเหตุว่าการใช้/regex/จะแยกขึ้นไป regexแต่ไม่รวมถึงเส้นที่ตรงกับ หากต้องการแยกและรวมถึงการจับคู่บรรทัดให้regexเพิ่ม+1ออฟเซ็ต:
csplit -sf file -n 1 large_file /XYZ/+1
นี้จะสร้างสองไฟล์ และfile0 file1หากคุณต้องการตั้งชื่ออย่างแน่นอนfile1และfile2คุณสามารถเพิ่มรูปแบบที่ว่างเปล่าลงในcsplitคำสั่งและลบไฟล์แรก:
csplit -sf file -n 1 large_file // /XYZ/+1
สร้างfile0, file1และfile2แต่file0เป็นที่ว่างเปล่าเพื่อให้คุณได้อย่างปลอดภัยสามารถลบออกได้:
rm -f file0
ด้วยความทันสมัยkshนี่คือตัวแปรเชลล์ (เช่นไม่มีsed) ของหนึ่งในsedคำตอบพื้นฐานด้านบน:
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
และอีกตัวแปรหนึ่งอยู่kshคนเดียว (เช่นยังละเว้นcat):
{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1
( kshดูเหมือนว่าวิธีการแก้ปัญหาที่แท้จริงจะค่อนข้าง performant; ในไฟล์ทดสอบ 2.4 GB มันต้องการ 19-21 วินาทีเมื่อเทียบกับ 39-47 วินาทีด้วยวิธีsed/ catตาม)
awkแสดงในเกณฑ์มาตรฐานของคุณเป็นอย่างไรบ้าง? และในขณะที่ฉันค่อนข้างแน่ใจว่าkshจะชนะการต่อสู้นี้เสมอหากคุณใช้ GNU sedคุณไม่ยุติธรรมมากsed- ปัญหาของ GNU -uนั้นเป็นวิธีที่ไม่ดีพอที่จะ POSIXLY ทำให้มั่นใจได้ว่าออฟเซ็ตของโปรแกรมจะออกจากโปรแกรม มัน - ไม่จำเป็นต้องชะลอการทำงานปกติของโปรแกรม - การบัฟเฟอร์นั้นดี - สิ่งที่sedควรทำคือดู descriptor เมื่อเสร็จแล้ว ไม่ว่าด้วยเหตุผลใด GNU จะยกเลิกความคิดนั้น
while; การพิมพ์จะกระทำโดยนัยตามผลข้างเคียงที่กำหนดไว้ของ<##ผู้ดำเนินการเปลี่ยนเส้นทาง และมีเพียงสายการจับคู่ที่จำเป็นต้องพิมพ์ (ด้วยวิธีนี้การใช้งานคุณสมบัติของเชลล์นั้นยืดหยุ่นที่สุดสำหรับการสนับสนุนรวม / excl.) การwhileวนลูปที่ชัดเจนที่ฉันคาดว่าจะช้าลงอย่างมาก (แต่ยังไม่ได้ตรวจสอบ)
headแทนread; ดูเหมือนว่าเพียงเล็กน้อยช้า แต่มันรหัส { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3terser:
{ sed '/XYZ/q' >file1; cat >file2; } <infile
ด้วย GNU sedคุณควรใช้-uสวิตช์ nbuffered ส่วนใหญ่อื่น ๆsedก็ควรทำงานแม้ว่า
หากต้องการออกจาก XYZ ...
{ sed -n '/XYZ/q;p'; cat >file2; } <infile >file1
ลองด้วย GNU sed:
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
การแฮ็กที่ง่ายคือการพิมพ์ไปที่ STDOUT หรือ STDERR ขึ้นอยู่กับว่ารูปแบบเป้าหมายได้รับการจับคู่หรือไม่ จากนั้นคุณสามารถใช้โอเปอเรเตอร์การเปลี่ยนเส้นทางของเชลล์เพื่อเปลี่ยนทิศทางเอาต์พุตได้ ตัวอย่างเช่นใน Perl สมมติว่าไฟล์อินพุตถูกเรียกใช้fและไฟล์เอาต์พุตสองไฟล์f1และf2:
ทิ้งบรรทัดที่ตรงกับรูปแบบการแยก:
perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2รวมถึงการจับคู่สาย:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2หรือมิฉะนั้นให้พิมพ์ไปที่ตัวจัดการไฟล์ต่าง ๆ :
ทิ้งบรรทัดที่ตรงกับรูปแบบการแยก:
perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
รวมถึงการจับคู่สาย:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZรวมสายในเอาท์พุทหรือไม่?