Есть ли что-нибудь быстрее, чем `найти. | wc -l` для подсчета файлов в каталоге?

8

Нередко мне приходится подсчитывать количество файлов в каталоге, иногда это исчисляется миллионами.

Есть ли лучший способ, чем просто перечислять и считать их find . | wc -l? Есть ли какой-нибудь вызов файловой системы, который вы можете сделать в ext3 / 4, который требует меньше операций ввода-вывода?

MattPark
источник
3
Вы считаете не только файлы, но и каталоги. Если вы хотите только считать файлы, используйте «find. -Type f | wc -l», если вы хотите считать символические ссылки и обычные файлы, используйте «find. -Type f -or -type l | wc -l»
FSMaxB
Каталог является своего рода файлом, как устройства, символические ссылки и сокеты. Обычные файлы - это подмножество файлов.
Тоби Спейт
1
Пример, который вы приводите, предполагает, что вы хотите рекурсивный подсчет - если нет, то вам нужно find -maxdepth 1. Обратите внимание, что при текущем подходе вы будете дважды считать любое имя, которое содержит символ новой строки.
Тоби Спейт

Ответы:

13

Не фундаментальное ускорение, но хоть что-то :)

find . -printf \\n | wc -l

Вам действительно не нужно передавать список имен файлов, достаточно только новых строк. Этот вариант примерно на 15% быстрее в моем Ubuntu 12.04.3, когда каталоги кэшируются в ОЗУ. Кроме того, этот вариант будет корректно работать с именами файлов, содержащими переводы строк.

Интересно, что этот вариант выглядит немного медленнее, чем приведенный выше:

find . -printf x | wc -c

Особый случай - но очень быстро

Если каталог находится в собственной файловой системе, вы можете просто посчитать inode:

df -i .

Если количество каталогов и файлов в других каталогах, отличных от подсчитанного, не сильно меняется, вы можете просто вычесть это известное число из текущего df -iрезультата. Таким образом, вы сможете очень быстро считать файлы и каталоги.

pabouk
источник
«Этот вариант примерно на 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, принесут наибольшую пользу
  • скорость произвольного доступа: жесткие диски выигрывают гораздо больше, чем твердотельные накопители
  • макет каталога: чем больше количество вложенных каталогов, тем больше потенциал оптимизации

(повторное) монтирование с использованием relatimeили даже nodiratimeможет повысить скорость (для всех методов), когда в противном случае доступ может привести к обновлению метаданных.

the8472
источник
Последнее предложение - полезный совет! Я думаю, что ссылка на вашу программу будет улучшена, если вы добавите краткое описание того, как она работает. Мы предпочитаем ответы, которые являются полными сами по себе, в случае, если со связанным ресурсом случится что-то плохое (но, конечно, также сохраните ссылку).
Тоби Спейт
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
MariusMatutiae
источник
Я думаю, что проблема с ls заключается в том, что он часто возвращает что-то вроде, /bin/ls: Argument list too longесли вы используете globbing, но опять же он может работать рекурсивно, как find также, так что, возможно, это то, что нужно учитывать, не используйте find, если не нужно.
MattPark
Кажется, что уже поздно (много лет) комментировать это, но ls -Aперечислить только файлы в текущем каталоге, в то время как findбез -maxdepth 1аргументов произойдет рекурсивный поиск по всем подкаталогам.
Лучано