ฉันมีไฟล์ 10k + รวมกว่า 20GB ที่ฉันต้องต่อกันเป็นไฟล์เดียว
มีวิธีที่เร็วกว่า
cat input_file* >> out
?
วิธีที่ต้องการจะเป็นคำสั่ง bash, Python เป็นที่ยอมรับเช่นกันหากไม่ช้ากว่านี้มาก
ฉันมีไฟล์ 10k + รวมกว่า 20GB ที่ฉันต้องต่อกันเป็นไฟล์เดียว
มีวิธีที่เร็วกว่า
cat input_file* >> out
?
วิธีที่ต้องการจะเป็นคำสั่ง bash, Python เป็นที่ยอมรับเช่นกันหากไม่ช้ากว่านี้มาก
คำตอบ:
ไม่ใช่แมวเป็นวิธีที่ดีที่สุดในการทำเช่นนี้ ทำไมต้องใช้ python เมื่อมีโปรแกรมที่เขียนไว้ใน C เพื่อจุดประสงค์นี้? แต่คุณ แต่อาจต้องการพิจารณาใช้xargs
ในกรณีที่มีความยาวบรรทัดคำสั่งเกินและคุณต้องมากกว่าหนึ่งARG_MAX
cat
การใช้เครื่องมือ GNU นี้เทียบเท่ากับสิ่งที่คุณมีอยู่แล้ว:
find . -maxdepth 1 -type f -name 'input_file*' -print0 |
sort -z |
xargs -0 cat -- >>out
find
sort
หากไม่มีสิ่งนี้ไฟล์จะแสดงรายการตามลำดับโดยพลการ (กำหนดโดยระบบไฟล์ซึ่งอาจเป็นลำดับการสร้างไฟล์)
bash
กลม มิฉะนั้นฉันไม่เห็นกรณีใด ๆ ที่xargs
หรือcat
จะไม่ทำงานตามที่คาดไว้
xargs
จะโทรหาเท่าcat
ที่จำเป็นเพื่อหลีกเลี่ยงข้อผิดพลาด E2BIG ของ execve (2)
การจัดสรรพื้นที่สำหรับไฟล์เอาต์พุตก่อนอาจปรับปรุงความเร็วโดยรวมเนื่องจากระบบไม่จำเป็นต้องอัพเดตการจัดสรรสำหรับการเขียนทุกครั้ง
ตัวอย่างเช่นหากบน Linux:
size=$({ find . -maxdepth 1 -type f -name 'input_file*' -printf '%s+'; echo 0;} | bc)
fallocate -l "$size" out &&
find . -maxdepth 1 -type f -name 'input_file*' -print0 |
sort -z | xargs -r0 cat 1<> out
ข้อดีอีกอย่างคือถ้ามีพื้นที่ว่างไม่เพียงพอจะไม่พยายามคัดลอก
หากเปิดbtrfs
คุณสามารถcopy --reflink=always
เปิดไฟล์แรกได้ (ซึ่งไม่มีนัยในการคัดลอกข้อมูลและจะทำให้เกือบจะทันที) และผนวกส่วนที่เหลือ หากมี 10,000 ไฟล์นั่นอาจจะไม่สร้างความแตกต่างมากนักเว้นแต่ว่าไฟล์แรกจะมีขนาดใหญ่มาก
มี API เพื่อสรุปว่าการคัดลอกไฟล์ทั้งหมด ( BTRFS_IOC_CLONE_RANGE
ioctl
) แต่ฉันไม่พบยูทิลิตีใด ๆ ที่เปิดเผย API นั้นดังนั้นคุณต้องทำใน C (หรือpython
ภาษาอื่น ๆ ที่พวกเขาสามารถเรียกได้เองioctl
) .
หากไฟล์ต้นฉบับกระจัดกระจายหรือมีลำดับอักขระ NUL จำนวนมากคุณสามารถสร้างไฟล์เอาต์พุตแบบกระจาย (ประหยัดเวลาและพื้นที่ดิสก์) ด้วย (ในระบบ GNU):
find . -maxdepth 1 -type f -name 'input_file*' -print0 |
sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
>
มิได้>>
แต่1<>
ที่ผมกล่าวว่าจะเขียนลงในแฟ้ม
<>
เป็นตัวดำเนินการเปลี่ยนเส้นทางการอ่าน + เขียนแบบ Bourne / POSIX มาตรฐาน ดูคู่มือเชลล์ของคุณหรือข้อมูลจำเพาะ POSIXสำหรับรายละเอียด เริ่มต้นfd
เป็น0
สำหรับ<>
ผู้ประกอบการ ( <>
สั้นสำหรับ0<>
เช่น<
สั้นสำหรับ0<
และ>
สั้น1>
) ดังนั้นคุณจำเป็นต้องมี1
การเปลี่ยนเส้นทาง stdout อย่างชัดเจน ที่นี่มีไม่มากที่เราต้องการอ่าน + เขียน ( O_RDWR
) แต่เราไม่ต้องการO_TRUNC
(เหมือนใน>
) ซึ่งจะยกเลิกการจัดสรรสิ่งที่เราเพิ่งจัดสรร
dd
หรือผ่านการอ่าน
fallocate
จะลบล้างค่าใช้จ่ายส่วนเกินfind
แม้ว่ามันจะเร็วขึ้นในรอบที่สอง btrfs
แน่นอนเปิดขึ้นเป็นไปได้ที่น่าสนใจว่า
find
ไม่เรียงลำดับไฟล์เหมือน shell glob