Найти количество файлов в каталоге

есть ли какой-либо метод в Linux для вычисления количества файлов в каталоге (то есть непосредственных потомков) в O(1) (независимо от количества файлов) без необходимости перечислять каталог первым? Если нет O (1), Есть ли разумно эффективный способ?

Я ищу альтернативу ls | wc -l.

8 ответов


readdir не так дорого, как вы можете подумать. Умение избежать статирования каждого файла и (необязательно) сортировки выходных данных ls.

/bin/ls -1U | wc -l

избегает псевдонимов в вашей оболочке, не сортирует вывод и перечисляет 1 файл на строку (не обязательно при транспортировке вывода в wc).

исходный вопрос можно перефразировать, как "структура данных хранилища количество записей?- на что ответ отрицательный. Нет более эффективный способ подсчета файлов, чем readdir(2)/getdents (2).


можно получить количество подкаталогов данного каталога, не пересекая весь список, stat'ING(stat(1) или stat (2)) данного каталога и наблюдая количество ссылок на этот каталог. Данный каталог с N дочерними каталогами будет иметь количество ссылок N+2, Одна ссылка для ".."запись каждого подкаталога, плюс два для"." и." .- записи данного справочника.

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

команда" /bin/ls-1U " не получит все записи. Он получит только те записи справочника, которые не начинаются с точки (.) характер. Например, это не будет считаться ".файл "профиль" находится во многих каталогах login $HOME.

можно использовать команду "/bin/ls-f" или команду "/bin/ls-Ua", чтобы избежать сортировки и получить все записи.

возможно к сожалению, для ваших целей команда" /bin/ls-f "или команда" /bin/ls-Ua "также будут считать"." и." ."записи, которые есть в каждом каталоге. Вам придется вычесть 2 из подсчета, чтобы избежать подсчета этих двух записей, например, в следующем:

expr `/bin/ls -f | wc -l` - 2     # Those are back ticks, not single quotes.

параметр --format=single-column (-1) не требуется в команде "/bin/ls-Ua" при передаче вывода "ls", как в этом случае в "wc". Команда "ls" автоматически запишет свой вывод в один столбец, если выход не является терминалом.


на на ls не в POSIX, а в OS X's ls это имеет другое значение, чем GNU ls, который он делает -t и -l используйте время создания вместо времени модификации. -f находится в POSIX как расширение XSI. Руководство GNU ls описание -f as do not sort, enable -aU, disable -ls --color и -U as do not sort; list entries in directory order.

POSIX описывает -f такой:

заставить каждый аргумент интерпретироваться как каталог и перечислите имя, найденное в каждом слоте. Эта опция должна отключить -l, -t, -s и -r, и включится -a; порядок-это порядок, в котором записи отображаются в каталоге.

команды типа ls|wc -l дайте неправильный результат, когда имена файлов содержат новые строки.

в zsh вы можете сделать что-то вроде этого:

a=(*(DN));echo ${#a}

D (glob_dots) включает в себя файлы, имя которых начинается с точки и N (null_glob) приводит к тому, что команда не приводит к ошибке в пустом каталоге.

или то же самое в Баш:

shopt -s dotglob nullglob;a=(*);echo ${#a[@]}

если IFS содержит цифры ASCII, добавьте двойные кавычки вокруг ${#a[@]}. Добавить shopt -u failglob обеспечить failglob не установлено.

портативный вариант-использовать find:

find . ! -name . -prune|grep -c /

grep -c / можно заменить на wc -l если имена файлов не содержат переводов строк. ! -name . -prune является портативной альтернативой -mindepth 1 -maxdepth 1.

или вот еще одна альтернатива, которая обычно не включает файлы, имя которых начинается с точки:

set -- *;[ -e "" ]&&echo "$#"

команда выше, однако, включает файлы, имя которых начинается с периода, когда опция, как dotglob в bash или glob_dots в zsh установлен. Когда * не соответствует файлу, команда приводит к ошибке в zsh с настройками по умолчанию.


я использовал эту команду..работает как шарм..только чтобы изменить maxdepth..то есть подкаталоги

find * -maxdepth 0 -type d -exec sh -c "echo -n {} ' ' ; ls -lR {} | wc -l" \;

Я думаю, что вы можете иметь больше контроля над этим, используя find:

find <path> -maxdepth 1 -type f -printf "." | wc -c
  • find -maxdepth 1 не будет углубляться в иерархию файлов.
  • -type f позволяет фильтровать только файлы. Аналогично, вы можете использовать -type d для каталогов.
  • -printf "." печатает точку для каждого совпадения.
  • wc -c подсчитывает символы, поэтому он подсчитывает точки, созданные print... что означает подсчет количества файлов, существующих в данном путь.

насколько я знаю, лучшей альтернативы нет. Эта информация может быть вне темы для этого вопроса, и вы уже знаете, что под Linux (в целом под Unix) каталоги-это просто специальный файл, который содержит список других файлов (я понимаю, что точные детали будут зависеть от конкретной файловой системы, но это общая идея). И нет вызова, чтобы найти общее количество записей, не пересекая весь список. Пожалуйста, поправьте меня, если я ошибаюсь.


для всех файлов в текущем каталоге попробуйте это:

ls -lR * | wc -l

использовать ls -1 / wc-l