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


11

ฉันมีไฟล์ข้อความขนาดใหญ่ (ประมาณ 2GB) ฉันต้องการค้นหาห้ารายการและแทนที่การกระทำในไฟล์เดียวกันและต้องการทำสิ่งนี้ในคำสั่งเดียว ปกติฉันจะใช้ vim, เปิดไฟล์, ทำหนึ่งแทนที่ action, จากนั้นต่อไป, ฯลฯ มีหนึ่ง catch, ดังที่ฉันสังเกตเห็นว่าหลังจากสามหรือสี่การค้นหา vim ล่มเนื่องจากปัญหาหน่วยความจำ

นี่คือตัวอย่างของคำสั่งที่ฉันใช้ใน Vim:

:%s/www\.abcdef/www.test.abcdef/g 
:%s/www\.klmnop/www.test.klmnop/g

วิธีที่ดีที่สุดในการจัดการกับสิ่งนี้คืออะไร?

คำตอบ:


8

ฉันจะใช้ sed เช่นนี้

sed -i "s/www\.abcdef/www.test.abcdef/g;s/www\.kmlnop/www.test.klmnop/g;" yourfile.txt

-iตัวเลือกหมายถึงการแทนที่ "ในสถานที่" คุณสามารถบอกได้ว่าจะสร้างการสำรองข้อมูลของไฟล์ของคุณโดยให้ส่วนขยายให้กับตัวเลือกนี้ ( -i.bakจะทำการสำรองข้อมูล yourfile.txt เป็น yourfile.txt.bak)


เร็วเข้า! ไม่ใช่แค่คำตอบของคุณ ;-) แต่สคริปต์ที่มีการค้นหา 5 รายการและการแทนที่จะเร็วขึ้นประมาณ 10 เท่าเพียงแค่เปิดไฟล์ในกลุ่ม สิ่งหนึ่งที่ทำให้ฉันสับสน ตอนแรกฉันคิดว่าไฟล์. bak จะเป็นไฟล์ที่ถูกแก้ไข แต่เป็นของจริง
SPRBRN

ค้นหาสิบและแทนที่การกระทำ (ด้วยการเข้าชมนับพันครั้ง) ในไฟล์ 2GB ในครั้งเดียวไม่มีปัญหาเรื่องหน่วยความจำ น้อยกว่าสองนาทีบนเดสก์ท็อปทั่วไป - สุดยอด!
SPRBRN

คำถามหนึ่ง ... คุณสามารถหลีกเลี่ยงจุดในสตริงแทนที่ จำเป็นหรือไม่
SPRBRN

1
ยินดีต้อนรับคุณ @rxt :) sedที่จริงแล้วคุณกำลังขวาคุณสามารถใช้จุดที่ไม่ใช่หนีในสตริงทดแทนใน ฉันพยายามและมันใช้งานได้ มีเธรดที่ดีในUnix & Linux Stackexchangeและคำตอบที่ได้รับการยอมรับไม่ได้กล่าวถึงจุดเป็นตัวละครที่จะหลบหนี
ssssteffff

2
@rxt คุณพูดว่าแทนที่สตริงขออภัยคุณไม่จำเป็นต้องหลบหนีจากที่นั่น
terdon

6

หากคุณมีรูปแบบการค้นหาอื่น ๆ อีกมากมายคุณสามารถบันทึกไว้ในไฟล์และอ่านการแทนที่จากที่นั่น ตัวอย่างเช่นสมมติว่าเนื้อหาเหล่านี้เป็นของreplacements.txt:

www\.abcdef www.test.abcdef 
www\.klmnop www.test.klmnop

จากนั้นคุณสามารถอ่านรายการการแทนที่ N และแทนที่ด้วยสิ่งนี้:

while read from to; do
  sed -i "s/$from/$to/" infile.txt ; 
done < replacements.txt 

หมายเหตุ:

  • นี้จะถือว่าสตริงการค้นหาของคุณไม่ได้มีช่องว่างและตัวอักษรแปลก ๆ replacements.txtจะต้องมีการหนี
  • มันจะเรียกใช้หนึ่งครั้งsedต่อการทดแทนซึ่งอาจใช้เวลาสักครู่หากคุณมีการดำเนินการทดแทนมากมาย
  • มันสามารถจัดการกับจำนวนการแทนที่โดยพลการ (หลายพันหรือหลายล้านหรืออะไรก็ตาม) ตราบใดที่คุณไม่ทราบว่าจะใช้เวลาเพิ่มอีกสักนิด

ตัวเลือกอื่นจะเขียนข้างต้นเป็นsedสคริปต์:

s/www\.abcdef/www\.test\.abcdef/g;
s/www\.kmlnop/www\.test\.klmnop/g;
s/aaaa/bbbb/g;
s/cccc/dddd/g;
s/eeee/ffff/g;

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

sed -f replace.sed infile.txt 

+1 สำหรับตัวเลือกอื่น ๆ '' อาจมีประโยชน์หากมีการเปลี่ยนที่เก็บไว้ในไฟล์! (ฉันหวังว่าฉันจะจำได้ว่า ... )
mpy

+1 สำหรับ "ตัวเลือกอื่น ๆ " เนื่องจากใช้ฟังก์ชันดั้งเดิมแทนสคริปต์ที่กำหนดเองดังนั้นจึงพกพา / แบ่งปันได้มากกว่า
David Cook

@DavidCook ขอบคุณ แต่มันไม่ได้เป็นแบบดั้งเดิมหรือแบบพกพาอีกแล้ว วิธีแรกคือการใช้เปลือก POSIX มันเป็นแบบพกพาเท่าที่สอง มันจะช้ากว่ามากเนื่องจากใช้ shell loop
terdon

คุณพูดถูกแล้วสิ่งที่ฉันหมายถึงคือรูปแบบไฟล์สคริปต์แบบพกพานั้นใช้งานได้มากกว่าเพราะมันใช้ฟังก์ชั่น sed ในตัวมากกว่าสคริปต์ซึ่งจะต้องแชร์ข้างๆไฟล์ replacements.txt อย่างไรก็ตามพวกเขาเป็นตัวเลือกที่ยอดเยี่ยม!
David Cook
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.