การลบส่วนหัวแบบแทนที่อย่างมีประสิทธิภาพสำหรับไฟล์ขนาดใหญ่โดยใช้ sed หรือไม่


24

คำสั่งด้านล่างอาจใช้เวลาหลายนาทีขึ้นอยู่กับขนาดไฟล์ มีวิธีอื่นอีกหรือไม่

sed -i 1d large_file 

คำตอบ:


34

ลองedแทน:

ed <<< $'1d\nwq' large_file

หากที่“ใหญ่” หมายถึงประมาณ 10 tailล้านเส้นหรือมากกว่าใช้ดีกว่า ไม่สามารถแก้ไขในสถานที่ได้ แต่ประสิทธิภาพของมันทำให้การขาดนั้นไม่สามารถให้อภัยได้:

tail -n +2 large_file > large_file.new

แก้ไขเพื่อแสดงความแตกต่างของเวลา:

( awkเพิ่มรหัสโดย Jaypal ให้มีเวลาดำเนินการในเครื่องเดียวกัน (CPU 2.2GHz))

bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped

bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s

bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s

bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s

bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s

bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s

ในกรณีของtailผมค่อนข้างจะนับเวลาที่จะทำทั้งสองเอาบรรทัดแรกและแทนที่ด้วยbigfile.txt bigfile.new
rozcietrzewiacz

@rozcietrzewiacz จุดของคุณถูกต้อง ขอขอบคุณ. Updated
จัดการ

นี่มันเจ๋งจริงๆ! ฉันทำแบบเดียวกันกับawkและได้ผลลัพธ์ต่อไปนี้ -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
jaypal singh

1
@ Jaypal ฉันเพิ่มรหัสของคุณในรายการทางเลือก บนเครื่องของฉันมันเร็วยิ่งขึ้น แปลกผมคาดว่าawkผลการดำเนินงานที่จะได้ใกล้ชิดกับsed's (หมายเหตุสำหรับตัวเอง: ไม่เคยคาดหวัง - ทดสอบแทน)
จัดการ

นี่เป็นทางออกที่ดีที่สุดในกรณีของฉัน: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;ฉันใช้ไฟล์เดียวกับล็อคเพื่อติดตามรายการงานเดียวที่ใช้โดยหลายกระบวนการ ฉันเริ่มด้วยการใช้โปสเตอร์เริ่มต้น: sed -i 1d large_file . นั่นเป็นสาเหตุให้ไฟล์ล็อคเป็นเวลา 1-2 วินาที tail/mvเสร็จสมบูรณ์คำสั่งผสมเกือบจะทันที ขอขอบคุณ!
Chris Adams

6

ไม่มีวิธีที่จะลบสิ่งต่าง ๆ ได้อย่างมีประสิทธิภาพตั้งแต่เริ่มต้นไฟล์ การลบข้อมูลจากจุดเริ่มต้นต้องเขียนไฟล์ใหม่ทั้งหมด

การตัดออกจากจุดสิ้นสุดของไฟล์สามารถทำได้อย่างรวดเร็วมาก (ระบบปฏิบัติการจะต้องปรับข้อมูลขนาดไฟล์ซึ่งอาจเป็นการล้างบล็อคที่ไม่ได้ใช้ตอนนี้) โดยทั่วไปไม่สามารถทำได้เมื่อคุณพยายามลบออกจากส่วนหัวของไฟล์

ในทางทฤษฎีอาจเป็น "เร็ว" ถ้าคุณลบทั้งบล็อก / ขอบเขตอย่างแน่นอน แต่ไม่มีการเรียกระบบสำหรับสิ่งนั้นดังนั้นคุณต้องพึ่งพาความหมายเฉพาะของระบบไฟล์ (ถ้ามีอยู่) (หรือมีรูปแบบของการชดเชยภายในบล็อก / ขอบเขตแรกเพื่อทำเครื่องหมายจุดเริ่มต้นที่แท้จริงของไฟล์ฉันเดาไม่เคยได้ยินมาก่อนเช่นกัน)


หากไฟล์มีขนาดใหญ่มากค่าโสหุ้ย I / O มีแนวโน้มที่จะสูงกว่าค่าโสหุ้ยของ CPU ที่ต้องใช้ในการดำเนินการสิ้นสุดบรรทัด
Mat

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

2
ฉันประหลาดใจที่ความแตกต่างนั้นใหญ่มากในผลลัพธ์ของคุณและสามารถทำซ้ำได้ด้วยขนาดไฟล์ที่นี่ ประโยชน์ที่ได้รับดูเหมือนจะลดลงเมื่อขนาดไฟล์เพิ่มขึ้น (ลองใช้ seq 10M, 15s สำหรับ sed, 5s สำหรับ ed) เคล็ดลับที่ดีอยู่แล้ว (+1)
Mat

เริ่มจากเวอร์ชัน 3.15 ตอนนี้ Linux มี API เพื่อยุบส่วนของไฟล์ในระบบไฟล์ที่มีขอบเขต แต่อย่างน้อยสำหรับ ext4 ที่สามารถทำได้บน full block (โดยปกติคือ 4k)
Stéphane Chazelas

แม้ว่าการแก้ไขจะต้องเขียนไฟล์ใหม่ทั้งหมด แต่บางครั้งก็มีประโยชน์มากที่จะมีเครื่องมือบรรทัดคำสั่งเพื่อแก้ไขอย่างมีประสิทธิภาพ ในกรณีของฉันสิ่งนี้ช่วยได้เมื่อฉันต้องลบบรรทัดแรกของไฟล์ที่มีขนาดใหญ่กว่าแรมระบบทั้งหมดของฉัน
Jason

3

วิธีที่มีประสิทธิภาพที่สุดอย่าทำ! หากคุณทำเช่นนั้นคุณต้องใช้พื้นที่ 'ใหญ่' สองเท่าในดิสก์และคุณเสีย IOs

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

tail -n +2 | your_program

เมื่อคุณต้องการอ่านไฟล์คุณสามารถใช้โอกาสในการลบบรรทัดที่ 1 แต่ถ้าคุณมีพื้นที่ที่ต้องการบนดิสก์:

tail -n +2 | tee large_file2 | your_program

หากคุณไม่สามารถอ่านจาก stdin ให้ใช้ Fifo:

mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line

ดียิ่งขึ้นถ้าคุณใช้ทุบตีใช้ประโยชน์จากการทดแทนกระบวนการ:

your_program -i <(tail -n +2 large_file)

หากคุณต้องการค้นหาไฟล์ฉันไม่เห็นทางออกที่ดีไปกว่าการไม่ติดกับไฟล์ในตอนแรก หากไฟล์นี้ถูกสร้างโดย stdout:

large_file_generator | tail -n +2 > large_file

มิฉะนั้นจะมีวิธีแก้ปัญหาการแทนที่ Fifo หรือกระบวนการเสมอ:

mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file

large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)


0

นี่เป็นเพียงทฤษฎี แต่ ...

ระบบไฟล์ที่กำหนดเอง (ดำเนินการโดยใช้ FUSE หรือกลไกที่คล้ายกัน) สามารถเปิดเผยไดเรกทอรีที่มีเนื้อหาเหมือนกับไดเรกทอรีที่มีอยู่แล้วที่อื่น แต่มีไฟล์ที่ถูกตัดทอนตามที่คุณต้องการ ระบบไฟล์จะแปลไฟล์ออฟเซ็ตทั้งหมด จากนั้นคุณจะไม่ต้องเขียนไฟล์ใหม่เสียเวลา

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

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