แทนที่ข้อความอย่างรวดเร็วในไฟล์ที่มีขนาดใหญ่มาก


25

ฉันมีไฟล์ข้อความ 25GB ที่ต้องการสตริงแทนที่ในไม่กี่บรรทัด ฉันสามารถใช้งานได้sedสำเร็จ แต่ใช้เวลาในการรันนานมาก

sed -i 's|old text|new text|g' gigantic_file.sql

มีวิธีที่เร็วกว่าในการทำเช่นนี้?


คุณรู้หมายเลขบรรทัดที่ข้อความที่จะแทนที่คืออะไร? หากไม่ใช่ตัวเลือกเดียวของคุณในการเร่งเครื่องคอมพิวเตอร์ของคุณให้เร็วขึ้น ความจริงที่ว่าคุณมีข้อมูลจำนวนมากหมายความว่าจะใช้เวลานานในการค้นหาข้อมูล
David King

ฉันสามารถ grep สำหรับหมายเลขบรรทัดได้อย่างรวดเร็วดังนั้นใช่
eisaacson

นอกจากนี้คุณยังสามารถใช้แกน CPU หลายตัวเพื่อเร่งความเร็วได้ - rankfocus.com/use-cpu-cores-linux-commands
ahaswer

อย่าใช้ sed สำหรับไฟล์ขนาดใหญ่ ลองดูvi หรือกลุ่มแทน
MikeJRamsey56

คำตอบ:


26

คุณสามารถลอง:

sed -i '/old text/ s//new text/g' gigantic_file.sql

จากการอ้างอิงนี้:

การเพิ่มประสิทธิภาพความเร็ว: หากต้องการเพิ่มความเร็วในการเรียกใช้งาน (เนื่องจากไฟล์อินพุตขนาดใหญ่หรือตัวประมวลผลช้าหรือฮาร์ดดิสก์) การทดแทนจะถูกดำเนินการอย่างรวดเร็วยิ่งขึ้นหากระบุนิพจน์ "ค้นหา" ไว้ก่อนที่จะกำหนด "s /.../" ../" คำแนะนำ.

นี่คือการเปรียบเทียบไฟล์ 10G ก่อน:

$ time sed -i 's/original/ketan/g' wiki10gb
real    5m14.823s
user    1m42.732s
sys     1m51.123s

หลังจาก:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s

สุดท้ายsedคือสะกดผิด ฉันแก้ไขโพสต์เมื่อวานนี้ในการแก้ไขปัญหาที่ผ่านมาsedคำสั่งที่ควรจะเป็นและไม่ได้time sed -i '/original/ s//ketan/g' wiki10gb time sed -i '/ketan/ s//original/g' wiki10gbฉันคืนค่าการแก้ไขของฉันในวันนี้เพราะ 1. เวลาไม่ตรงกับคำสั่งและ 2. ฉันได้ทำการทดสอบเดียวกันกับ GNU บนไฟล์ 3+ GB และฉันไม่สังเกตเห็นความแตกต่างระหว่างสองsedทางเลือก ฉันสงสัยว่าความแตกต่างในบางครั้งเกิดจากการสะกดคำผิด
xhienne

@xhienne ฉันไม่แน่ใจว่าคุณหมายถึงอะไรด้วยการสะกดคำผิด ในการเรียกใช้ครั้งแรกฉันจะแทนที่คำว่า 'ดั้งเดิม' ด้วย 'ketan' และในคำที่สองที่ฉันใช้แทนคำว่า 'ketan' ด้วยคำว่า 'ดั้งเดิม' ทำให้เกิดการแทนจำนวนเท่ากันทั้งสองกรณี
mkc

1
ฉันกำลังใช้ "แก้ไข" ที่รายงานโดยผู้ใช้รายใหม่ที่มีชื่อเสียงไม่เพียงพอ ตอนนี้ฉันเข้าใจสิ่งที่คุณทำ อย่างไรก็ตามถ้าคุณต้องการพิสูจน์ว่าไวยากรณ์หนึ่งดีกว่าอีกอันคุณต้องทำการดำเนินการเดียวกันแน่นอนซึ่งไม่ใช่กรณีที่นี่ (CPU-wise การค้นหาสตริง 5-char ไม่เหมือนกับการค้นหา สตริง 7 อักขระ) ยิ่งกว่านั้นการทดสอบไฟล์ 10GB ชนิดนี้ขึ้นอยู่กับโหลดของเครื่องของคุณเป็นอย่างมาก (CPU, ดิสก์) ฉันเห็นความผันผวนอย่างมากในtimeผลลัพธ์เป็นการส่วนตัว แต่โดยรวมแล้วไม่มีความแตกต่างในเวลา
xhienne

ฉันเชื่อว่าสิ่งนี้เกี่ยวข้อง - ดูคำตอบที่ยอมรับได้ที่นี่stackoverflow.com/questions/11145270/… >> sed สตรีมไฟล์ทั้งหมด แต่ดังที่ระบุไว้ในคำตอบนี้การระบุหมายเลขบรรทัด (ถ้าทราบ) ช่วย: ในกรณีของฉัน ความเร็วในการประมวลผลเพิ่มขึ้น 2 เท่า (GNU sed 4.5) คุณสามารถ grep -n หรือ ripgrep (rg) เพื่อค้นหาหมายเลขบรรทัดตามการค้นหารูปแบบ ผลการระบุหมายเลขบรรทัดก็เหมือนมีผลการค้นหาในไฟล์นั้นตามคำตอบข้างต้น
Victoria Stuart

1

คำตอบสั้น ๆ คือ "ไม่" - ปัจจัย จำกัด ของคุณในการดำเนินการเช่นนี้คือดิสก์ IO ไม่มีวิธีใดที่จะสตรีมดิสก์ 25GB เร็วขึ้น คุณอาจได้รับการปรับปรุงเล็กน้อยหากคุณไม่แก้ไขในสถานที่และเขียนผลลัพธ์ของsedไดรฟ์แยกต่างหาก (ถ้าคุณมีหนึ่งที่มีอยู่) - เนื่องจากวิธีที่คุณสามารถอ่านจากที่หนึ่งในขณะที่เขียนไปยังอีกและมีเล็กน้อย ความขัดแย้งน้อยลงเป็นผล

คุณอาจจะสามารถเพิ่มความเร็วขึ้นเล็กน้อยโดยไม่ใช้เครื่องมือ regex สำหรับแต่ละบรรทัด - ดังนั้นสำหรับตัวอย่างการใช้ Perl (ผมค่อนข้างมั่นใจว่าคุณสามารถทำเช่นนี้กับsedแต่ผมไม่ทราบว่าไวยากรณ์) - นี้จะเริ่มต้นจาก สาย 10,000 เป็นต้นไป

perl -pe '$. > 10_000 && s/old_text/new_text/g' 

และถ้ามีการจัดเรียงของภาวะแทรกซ้อนใด ๆ ในเรื่องนี้ (metacharacters) แล้วลดการเหล่านั้นจะเล็กน้อยในการปรับปรุงประสิทธิภาพของเครื่องยนต์ regex ไม่


1
ใน sed ที่จะเป็นsed -i '10000,$ s/old_text/new_text/g'
Dani_l

น่ารัก ฉันไม่รู้ว่าจะsedเปรียบเทียบอย่างไร- ฉันถือว่าเร็วกว่าเล็กน้อย แต่ไม่มากเพราะขนาดไฟล์
Sobrique

ฉันคิดว่า Perl เร็วกว่า sed แต่ sed ค่อนข้างลึกลับน้อยกว่าหรือต้องการเส้นโค้งการเรียนรู้เริ่มต้นน้อยกว่า
Dani_l

1
ดูตอนนี้ฉันได้กล่าวว่าตรงข้าม - คุณสามารถ (เกือบ) เขียนsedในperlแต่หลังยังช่วยให้คุณเขียนมากขึ้น verbose สคริปต์เกินไป
Sobrique

0

หากข้อความใหม่และเก่ามีความยาวเท่ากันคุณสามารถค้นหาไฟล์และเขียนเฉพาะไบต์ที่มีการเปลี่ยนแปลงแทนการคัดลอกไฟล์ทั้งหมด ไม่เช่นนั้นคุณจะติดกับการย้ายข้อมูลจำนวนมาก

หมายเหตุ: นี่เป็นเรื่องยุ่งยากและเกี่ยวข้องกับการเขียนรหัสที่กำหนดเอง

ดู man page สำหรับ fseek หากคุณทำงานใน C หรือ C ++ หรือภาษาที่คุณโปรดปรานสำหรับการค้นหาและเขียนการโทรของระบบ

หากคุณยืนยันในการใช้บรรทัดคำสั่งเท่านั้นและคุณสามารถรับค่าออฟเซ็ตของข้อความได้คุณสามารถเขียนข้อความแทนที่ด้วยคำสั่ง "dd" ที่เขียนอย่างระมัดระวัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.