Найти количество файлов в каталоге
есть ли какой-либо метод в 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) каталоги-это просто специальный файл, который содержит список других файлов (я понимаю, что точные детали будут зависеть от конкретной файловой системы, но это общая идея). И нет вызова, чтобы найти общее количество записей, не пересекая весь список. Пожалуйста, поправьте меня, если я ошибаюсь.