Чи є щось швидше, ніж `знайти. | wc -l` для підрахунку файлів у каталозі?


8

Не рідко мені доводиться рахувати кількість файлів у каталозі, іноді це налічує мільйони.

Чи є кращий спосіб, ніж просто перерахувати та порахувати їх find . | wc -l? Чи є якийсь виклик файлової системи, який ви можете здійснити на ext3 / 4, що менш інтенсивно вводить-виводить?


3
Ви рахуєте не лише файли, але й каталоги. Якщо ви хочете лише рахувати файли, використовуйте "find. -Type f | wc -l", якщо ви хочете рахувати символічні посилання та звичайні файли, використовуйте "find. -Type f -or -type l | wc -l"
FSMaxB

Каталог - це такий самий файл, як і пристрої, символьні посилання та сокети. Регулярні файли - це підмножина файлів.
Toby Speight

1
Приклад, який ви наводите, говорить про те, що ви хочете рекурсивного підрахунку - якщо ні, то вам потрібно find -maxdepth 1. Зауважте, що при вашому поточному підході ви подвійно будете рахувати будь-яке ім’я, що містить символ нового рядка.
Toby Speight

Відповіді:


13

Не принципова швидкість, але хоча б щось :)

find . -printf \\n | wc -l

Вам дійсно не потрібно передавати список імен файлів, достатньо лише нових рядків. Цей варіант на 15% швидший на моєму Ubuntu 12.04.3, коли каталоги кешуються в ОЗУ. Крім того, цей варіант буде коректно працювати з іменами файлів, що містять нові рядки.

Цікаво, що цей варіант здається трохи повільнішим, ніж описаний вище:

find . -printf x | wc -c

Особливий випадок - але дуже швидко

Якщо каталог знаходиться у власній файловій системі, ви можете просто порахувати вставки:

df -i .

Якщо кількість каталогів і файлів в інших каталогах, ніж нарахована, не сильно зміниться, ви можете просто відняти це відоме число від поточного df -iрезультату. Таким чином ви зможете дуже швидко рахувати файли та каталоги.


"Цей варіант на 15% швидший ..." змушує мене замислитися, чи є якась зручна хитрість, яку ви використовуєте для того, щоб виправити це?
Брайан 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цією відповіддю.
пабук

3

Я написав ffcnt саме для цієї мети. Він отримує фізичне зміщення самих каталогів за допомогою fiemapioctl, а потім планує обхід каталогів у кількох послідовних пропусках, щоб зменшити випадковий доступ. Чи дійсно ви отримаєте прискорення порівняно з, find | wc залежить від кількох факторів:

  • Тип файлової системи: файлові системи, такі як ext4, які підтримують fiemapioctl, отримають найбільшу користь
  • випадкова швидкість доступу: жорсткі диски виграють набагато більше, ніж 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якщо ви використовуєте глобус, але знову ж таки він може працювати рекурсивно, як і find, тому, можливо, це щось, що слід врахувати, не використовуйте find, якщо не потрібно.
MattPark

Дуже пізно (багато років) коментувати це, але ls -Aперелік лише файлів у поточному каталозі, а findбез -maxdepth 1аргументів здійснить рекурсивний пошук у всіх підкаталогах.
Лучано
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.