Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

/bin/ls -1U | wc -l

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

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

Ответ 2

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

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

Команда "/bin/ls -1U" не получит все записи. Он получит только те записи каталога, которые не начинаются с символа точки (.). Например, он не будет считать файл ".profile", найденный во многих каталогах $HOME 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" будет автоматически записывать свой вывод в один столбец, если вывод не является терминалом.

Ответ 3

Параметр -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 с настройками по умолчанию.

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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