ฉันมีไฟล์ 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