มีอะไรเร็วกว่า `หา | wc -l` เพื่อนับไฟล์ในไดเรกทอรี?


8

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

มีวิธีที่ดีกว่าเพียงแค่แจงนับและนับมันด้วยfind . | wc -lหรือไม่? มีการเรียกระบบไฟล์บางชนิดที่คุณสามารถทำได้บน ext3 / 4 ที่มี I / O น้อยลงหรือไม่?


3
คุณกำลังนับไม่เพียง แต่ไฟล์ แต่รวมถึงไดเรกทอรีด้วย หากคุณต้องการนับไฟล์ให้ใช้ "find. -type f | wc -l" หากคุณต้องการนับลิงก์สัญลักษณ์และไฟล์ปกติให้ใช้ "find. -type f -or -type l | wc -l"
FSMaxB

ไดเรกทอรีเป็นชนิดของไฟล์เช่นเดียวกับอุปกรณ์ symlinks และซ็อกเก็ต ไฟล์ปกติเป็นส่วนย่อยของไฟล์
Toby Speight

1
ตัวอย่างที่คุณให้แสดงให้เห็นว่าคุณต้องการrecursiveนับ - find -maxdepth 1ถ้าไม่แล้วคุณจะต้อง โปรดทราบว่าด้วยวิธีการปัจจุบันของคุณคุณจะนับชื่อใด ๆ ที่มีอักขระขึ้นบรรทัดใหม่
Toby Speight

คำตอบ:


13

ไม่ใช่การเร่งความเร็วพื้นฐาน แต่อย่างน้อยก็มีบางอย่าง :)

find . -printf \\n | wc -l

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

สิ่งที่น่าสนใจตัวแปรนี้ดูเหมือนจะช้ากว่าที่กล่าวไว้ข้างต้นเล็กน้อย:

find . -printf x | wc -c

กรณีพิเศษ - แต่เร็วจริงๆ

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

df -i .

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


"ตัวแปรนี้เร็วขึ้นประมาณ 15% ... " ทำให้ฉันสงสัยว่ามีกลอุบายที่มีประโยชน์บางอย่างที่คุณใช้ในการทำสิ่งเหล่านี้หรือไม่?
Brian Z

4
@BrianZ: คุณสามารถตั้งเวลาคำสั่งโดยเตรียมคำสั่งให้พร้อมเวลา time find /usr/src/ -printf \\n | wc -lคุณสามารถล้างแคชในระหว่างรันด้วยsudo sync && sudo sysctl -w vm.drop_caches=3
MattPark

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

มี-printf xความหมายเหมือนกัน-printf '\0'ไหม? ฉันไม่เห็นมันกล่าวถึงในเอกสาร
CMCDragonkai

@CMCDragonkai: การกระทำ-printfคล้ายกับprintf()ฟังก์ชั่นใน C ที่มีความแตกต่างหลักที่%คำสั่งมีความหมายที่แตกต่างกัน การดำเนินการถูกเรียกใช้สำหรับทุกไฟล์ที่พบ ซึ่งหมายความว่า-printf xจะพิมพ์อักขระxสำหรับทุกไฟล์ที่พบ (ลองใช้!) และ-printf '\0'จะพิมพ์อักขระ NULL (รหัส ASCII 0) สำหรับทุกไฟล์ที่พบ -printf '\0'ไม่มีความหมายพิเศษ ทั้งสองจะทำงานเหมือนกันในตัวอย่างด้วยwc -cในคำตอบนี้
pabouk

3

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

  • ประเภทระบบไฟล์: ระบบไฟล์เช่น ext4 ซึ่งรองรับfiemapioctl จะได้รับประโยชน์มากที่สุด
  • ความเร็วในการเข้าถึงแบบสุ่ม: HDD ได้รับประโยชน์มากกว่า SSD
  • เค้าโครงไดเรกตอรี: ยิ่งมีจำนวนไดเร็กทอรีที่ซ้อนกันมากเท่าไหร่

(ใหม่) การติดตั้งด้วยrelatimeหรือnodiratimeอาจปรับปรุงความเร็ว (สำหรับวิธีการทั้งหมด) เมื่อการเข้าถึงอาจทำให้เกิดการปรับปรุงข้อมูลเมตา


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

2

ที่จริงแล้วในระบบของฉัน (Arch Linux) คำสั่งนี้

   ls -A | wc -l

เร็วกว่าที่กล่าวมาทั้งหมด:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

   real    0m0.007s
   user    0m0.000s
   sys     0m0.004s

ฉันคิดว่าปัญหาเกี่ยวกับ ls คือมันมักจะส่งคืนสิ่งที่ชอบ/bin/ls: Argument list too longถ้าคุณใช้ globbing แต่อีกครั้งมันสามารถทำงานซ้ำเช่น find ได้ดังนั้นบางทีมันอาจเป็นสิ่งที่ต้องพิจารณาอย่าใช้ find หากไม่จำเป็น
MattPark

ดูเหมือนว่าจะช้า (หลายปี) ที่จะแสดงความคิดเห็นเกี่ยวกับเรื่องนี้ แต่ls -Aแสดงเฉพาะไฟล์ในไดเรกทอรีปัจจุบันขณะที่findไม่มี-maxdepth 1อาร์กิวเมนต์จะทำการค้นหาแบบเรียกซ้ำผ่านไดเรกทอรีย่อยทั้งหมด
Luciano
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.