CentOS 5.9
Я столкнулся с проблемой на днях, когда в каталоге было много файлов. Чтобы посчитать это, я побежалls -l /foo/foo2/ | wc -l
Оказывается, в одном каталоге было более 1 миллиона файлов (длинная история - основная причина исправляется).
Мой вопрос: есть ли более быстрый способ сделать подсчет? Какой самый эффективный способ получить счет?
ls -l|wc -l
будет отключен на единицу из-за общего количества блоков в первой строкеls -l
вывода-A
флага.-l
также проблематично из-за чтения метаданных файла для создания расширенного формата списка. Принудительное использование NOT-l
с помощью\ls
гораздо более удобного варианта (-1
предполагается при выводе по конвейеру). См . Ответ Жиля для лучшего решения здесь.ls -l
не выводит никаких скрытых файлов , ни.
и..
записи.ls -a
вывод включает в себя скрытые файлы, в том числе.
и в..
то время какls -A
вывод включает в себя скрытые файлы, исключая.
и..
. В ответе Жиляdotglob
опция оболочки bash заставляет расширение включать скрытые файлы, исключая.
и..
.Ответы:
Краткий ответ:
(Это включает
.
и..
, так что вычтите 2.)Когда вы перечисляете файлы в каталоге, могут произойти три общие вещи:
ls
команда делают это.stat
для получения метаданных о каждой записи каталога, например, является ли он каталогом.№ 3, безусловно, самый дорогой, потому что он требует загрузки индекса для каждого файла. Для сравнения, все имена файлов, необходимые для # 1, компактно хранятся в нескольких блоках. # 2 тратит некоторое процессорное время, но часто это не прерывает сделки.
Если в именах файлов нет новых строк, простой
ls -A | wc -l
говорит вам, сколько файлов в каталоге. Помните, что если у вас есть псевдоним дляls
, это может вызвать вызовstat
(например,ls --color
или вамls -F
необходимо знать тип файла, для которого требуется вызовstat
), поэтому из командной строки вызывайтеcommand ls -A | wc -l
или\ls -A | wc -l
избегайте псевдонима.Если в имени файла есть новые строки, то будут ли новые строки перечислены или нет, зависит от варианта Unix. GNU coreutils и BusyBox по умолчанию отображают
?
новую строку, поэтому они в безопасности.Вызовите
ls -f
список записей без сортировки их (# 2). Это автоматически включается-a
(по крайней мере, в современных системах).-f
Вариант в POSIX , но с дополнительным статусом; большинство реализаций поддерживают его, но не BusyBox. Опция-q
заменяет непечатаемые символы, включая символы новой строки, на?
; это POSIX, но не поддерживается BusyBox, поэтому пропустите его, если вам нужна поддержка BusyBox за счет перерасчета файлов, имя которых содержит символ перевода строки.Если в каталоге нет подкаталогов, то большинство версий
find
не будут вызыватьstat
его записи (листовая оптимизация каталога: каталог с числом ссылок 2 не может иметь подкаталоги, поэтомуfind
не нужно искать метаданные записей, если только состояние такое как-type
требует). Таким образомfind . | wc -l
, это переносимый и быстрый способ подсчета файлов в каталоге, при условии, что в каталоге нет подкаталогов и что ни одно имя файла не содержит символ новой строки.Если в каталоге нет подкаталогов, но имена файлов могут содержать символы новой строки, попробуйте один из них (второй должен быть быстрее, если он поддерживается, но может быть не так заметно).
С другой стороны, не используйте,
find
если в каталоге есть подкаталоги: дажеfind . -maxdepth 1
вызовыstat
для каждой записи (по крайней мере, с GNU find и BusyBox find). Вы избегаете сортировки (# 2), но платите цену поиска по индоду (# 3), который снижает производительность.В оболочке без внешних инструментов вы можете запустить подсчет файлов в текущем каталоге с помощью
set -- *; echo $#
. Это пропускает точечные файлы (файлы, чье имя начинается с.
) и сообщает 1 вместо 0 в пустой директории. Это самый быстрый способ подсчета файлов в небольших каталогах, поскольку он не требует запуска внешней программы, но (за исключением zsh) тратит время на большие каталоги из-за шага сортировки (# 2).В bash это надежный способ подсчета файлов в текущем каталоге:
В ksh93 это надежный способ подсчета файлов в текущем каталоге:
В zsh это надежный способ подсчета файлов в текущем каталоге:
Если у вас есть
mark_dirs
набор опций, убедитесь , чтобы выключить его:a=(*(DNoN^M))
.В любой оболочке POSIX это надежный способ подсчета файлов в текущем каталоге:
Все эти методы сортируют имена файлов, кроме zsh.
источник
find -maxdepth 1
легко идет в ногу с тем,\ls -U
что вы не добавляете ничего, как-type
объявление, которое должно выполнять дополнительные проверки. Вы уверены, что GNU действительно находит звонкиstat
? Даже замедлениеfind -type
- ничто по сравнению с тем, сколькоls -l
болот, если вы заставите его возвращать детали файла. С другой стороны, победитель с чистой скоростьюzsh
использует несортировочный шар. (сортированные глобусы в 2 раза медленнее, чем несортируемые в 2ls
раза быстрее). Интересно, будут ли типы файловой системы значительно влиять на эти результаты.strace
. Это верно только в том случае, если в каталоге есть подкаталоги: в противном случаеfind
начинается оптимизация конечного каталога (даже без-maxdepth 1
), я должен был упомянуть об этом. На результат может повлиять множество факторов, в том числе тип файловой системы (вызовstat
в файловых системах, представляющих каталоги в виде линейных списков, обходится намного дороже, чем в файловых системах, представляющих каталоги в виде деревьев), независимо от того, все ли иноды были созданы вместе и, таким образом, находятся рядом. на диске, в холодном или горячем кеше и т. д.ls -f
это был надежный способ предотвратить вызовыstat
- сегодня это часто просто описывается как «вывод не отсортирован» (что он также вызывает), и включает в себя.
и..
.-A
и-U
не являются стандартными вариантами.\ls -afq *[0-9].pdb | wc -l
version sh (AT&T Research) 93u+ 2012-08-01
в моей системе на основе Debian,FIGNORE
похоже, не работает. В.
и..
записи включены в результирующий массивЭто значительно быстрее на моей машине, но локальный
.
каталог добавляется в счет.источник
-type
параметр,find
должно быть быстрее, чемls
-mindepth 1
чтобы пропустить сам каталог.ls -1U
прежде чем канал должен потратить немного меньше ресурсов, поскольку он не пытается сортировать записи файла, он просто читает их, когда они сортируются в папке на диске. Это также производит меньше продукции, что означает немного меньше работы дляwc
.Вы также можете использовать
ls -f
более или менее ярлык дляls -1aU
.Я не знаю, есть ли ресурсосберегающий способ сделать это с помощью команды без трубопровода, хотя.
источник
Еще одна точка сравнения. Хотя эта программа на С не является оболочкой-оболочкой, она не делает ничего лишнего. Обратите внимание, что скрытые файлы игнорируются, чтобы соответствовать выводу
ls|wc -l
(ls -l|wc -l
отключен на единицу из-за общего количества блоков в первой строке вывода).источник
readdir()
API stdio добавляет некоторые издержки и не дает вам контроля над размером буфера, передаваемого базовому системному вызову (getdents
в Linux)Вы могли бы попробовать
perl -e 'opendir($dh,".");$i=0;while(readdir $dh){$i++};print "$i\n";'
Было бы интересно сравнить время с вашей трубкой.
источник
find -maxdepth 1 | wc -l
,\ls -AU | wc -l
иzsh
по нестандартной сортировке Глоба и массив счета). Другими словами, он выбивает параметры с различными недостатками, такими как сортировка или чтение посторонних свойств файла. Рискну сказать, так как он тоже ничего вам не зарабатывает, не стоит использовать более простое решение, если вы уже не в Perl :).
и..
элементы каталога в счете, так что вам нужно вычесть два , чтобы получить фактическое количество файлов (и поддиректорий). В современном Perl,perl -E 'opendir $dh, "."; $i++ while readdir $dh; say $i - 2'
сделал бы это.Из этого ответа я могу думать об этом как о возможном решении.
Скопируйте вышеуказанную C-программу в каталог, в котором должны быть перечислены файлы. Затем выполните эти команды:
источник
ls -f
, вообще не фильтроватьd_type
, просто включатьd->d_ino != 0
; 3) вычесть 2 для.
а..
.ls -f
.Решение только для bash, не требующее какой-либо внешней программы, но не знаю, насколько оно эффективно:
источник
Вероятно, наиболее ресурсоэффективный способ не предусматривает никаких внешних вызовов процессов. Так что я бы поставил на ...
источник
После исправления проблемы из ответа @Joel, где она добавлена
.
в виде файла:find /foo/foo2 -maxdepth 1 | tail -n +2 | wc -l
tail
просто удаляет первую строку, то.
есть больше не учитывается.источник
wc
ввода не очень эффективно, поскольку накладные расходы линейно увеличиваются относительно размера ввода. В этом случае, почему не просто уменьшать окончательный подсчет , чтобы компенсировать за это время от одной, которая является постоянная время операции:echo $(( $(find /foo/foo2 -maxdepth 1 | wc -l) - 1))
let count = $(find /foo/foo2 -maxdepth 1 | wc -l) - 2
os.listdir () в python может сделать всю работу за вас. Это дает массив содержимого каталога, исключая специальный '.' и '..' файлы. Кроме того, нет необходимости беспокоиться о файлах abt со специальными символами, такими как '\ n' в имени.
Ниже приведено время, затрачиваемое приведенной выше командой python по сравнению с командой 'ls -Af'.
источник
ls -1 | wc -l
сразу приходит в голову. Является лиls -1U
это быстрее, чемls -1
чисто академический - разница должна быть незначительной, но для очень больших каталогов.источник
Чтобы исключить подкаталоги из подсчета, вот вариант принятого ответа от Жиля:
Внешнее
$(( ))
арифметическое расширение вычитает выход второй$( )
подоболочки из первого$( )
. Первый$( )
- это как раз Жиль сверху. Второй$( )
выводит количество каталогов, «связывающих» с целью. Это происходит изls -od
(заменитеls -ld
при желании), где столбец, который перечисляет количество жестких ссылок, имеет это как особое значение для каталогов. «Ссылка» включает в себя подсчет.
,..
и любые подкаталоги.Я не тестировал производительность, но, похоже, это похоже. Он добавляет статистику целевого каталога и некоторые накладные расходы для добавленных подоболочек и конвейера.
источник
Я думаю, что echo * будет более эффективным, чем любая команда 'ls':
источник
echo 'Hello World'|wc -w
производит2
.