Найти количество файлов в каталоге
Вопрос
Существует ли какой -либо метод в Linux для расчета количества файлов в каталоге (то есть непосредственных детей) в O (1) (независимо от количества файлов) без необходимости сначала перечислить каталог? Если не O (1), есть ли разумно эффективным способом?
Я ищу альтернативу ls | wc -l
.
Решение
Readdir не так дорого, как вы думаете. Круп, избегая статистики каждого файла и (необязательно) сортирует вывод LS.
/bin/ls -1U | wc -l
избегает псевдонимов в вашей оболочке, не сортирует выходные данные и перечисляет 1 файл на линию (не требует строго необходимости при передаче вывода в WC).
Первоначальный вопрос может быть перефразирован как «хранят ли структура данных каталога подсчет количества записей?», На что ответ - нет. Нет более эффективного способа подсчета файлов, чем readdir (2)/getDents (2).
Другие советы
Можно получить количество подкаталогов данного каталога, не пройдя весь список по статистике (стат (1) или статистике (2)) данного каталога и соблюда количества ссылок на этот каталог. В данном каталоге с N Kids Directory будет количество ссылок N+2, одна ссылка для «..» в записи каждого подкаталера, плюс два для «». и ".." Записи данного каталога.
Однако нельзя получить количество всех файлов (будь то обычные файлы или подкаталогов), не пройдя весь список - это правильно.
Команда "/bin/ls -1u" не получит все записи. Это получит Только Эти записи каталога, которые не начинаются с символа DOT (.). Например, он не будет считать файл «.profile», найденный во многих домашних каталогах Login $.
Можно использовать либо команду "/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 = одноконкурм (-1) не требуется в команде «/bin/ls -ua» при пропуске вывода «LS», как в «WC» в данном случае. Команда «LS» автоматически записывает свой вывод в одном столбце, если вывод не является терминалом.
А -U
вариант для ls
не в Posix, а в OS X ls
он имеет другое значение от GNU ls
, это то, что он делает -t
и -l
Используйте время создания вместо времени модификации. -f
находится в Posix как расширение XSI. Руководство GNU ls
описывает -f
в виде do not sort, enable -aU, disable -ls --color
и -U
в виде 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
) приводит к тому, что команда не приводит к ошибке в пустом каталоге.
Или то же самое в Bash:
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 "$1" ]&&echo "$#"
Приведенная выше команда включает в себя файлы, имя которого начинается с периода, когда такая опция dotglob
в Bash или glob_dots
в ZSH установлен. Когда *
Матч нет файла, команда приводит к ошибке в ZSH с настройками по умолчанию.
Я использовал эту команду .. заработанные как обаяние .. только чтобы изменить максимальный
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