find . -type f | wc -l считает все файлы внутри текущего каталога вместе с подпапками и не считает сами каталоги. Интереснее обычно разбивки — по расширениям и по подпапкам, — и есть один случай, когда wc -l врёт: имя файла с переносом строки.
1. Сколько файлов всего
$ clai сколько файлов в этой папке и во всех вложенных→ find . -type f | wc -l20
-type f отбрасывает каталоги и симлинки, поэтому число что-то значит. ls | wc -l в той же папке ответит 3: он видит только верхний уровень и считает каталоги как записи.
2. Разбивка по расширениям
$ clai посчитай файлы по расширениям→ find . -type f -name '*.*' | sed 's/.*\.//' | sort | uniq -c | sort -rn 7 jpg 6 py 4 md 1 txt 1 png 1 bin
Обычно это и есть настоящий вопрос: из чего вообще состоит каталог. -name '*.*' отбрасывает файлы без расширения — без него sed вернёт для них имя целиком.
3. Разбивка по подпапкам
$ clai посчитай файлы в каждой подпапке→ for d in */; do printf '%5s %s\n' "$(find "$d" -type f | wc -l)" "$d"; done 3 docs/ 8 img/ 7 src/
Цикл по каталогам верхнего уровня со счётом внутри каждого, рекурсивно. Скрытые каталоги под */ не подпадают — поэтому сумма меньше общего числа.
4. Без скрытых файлов
$ clai посчитай файлы, пропуская скрытые→ find . -type f -not -path '*/.*' | wc -l18
20 против 18 — ровно два точечных файла. -not -path '*/.*' заодно выкидывает всё содержимое скрытых каталогов вроде .git, а обычно именно это и имелось в виду.
5. Ловушка: перенос строки в имени
$ clai посчитай файлы надёжно, даже если в именах есть переносы строк→ find . -type f -printf '.' | wc -c21
Проверено на файле, имя которого занимает две строки: find . -type f | wc -l в том же каталоге отвечает 22. wc -l считает строки, а не файлы. -printf '.' печатает по точке на файл, и счёт снова верный. Переносимый вариант без GNU-расширений — find . -type f -print0 | tr -dc '\0' | wc -c.
6. Файлы и каталоги одной строкой
$ clai покажи сколько здесь файлов и сколько каталогов→ printf 'files: %s\ndirs: %s\n' "$(find . -type f | wc -l)" "$(find . -type d | wc -l)"
-type d считает и сам текущий каталог, поэтому каталогов всегда на один больше, чем ожидаешь.
Gotchas
ls | wc -lсчитает не то. Он не заходит в подпапки, зато считает каталоги и пропускает точечные файлы. На заданный вопрос отвечаетfind -type f.wc -lломается на переносах строк в именах. Проверено: файлов 21, ответ 22. Если каталог пришёл извне — от пользователей, из архива, от парсера, — считайте через-printf '.'или-print0.find .заходит в скрытые каталоги. В репозитории один.gitдобавит к итогу тысячи файлов. Фильтруйте через-not -path '*/.*', иначе число ничего не значит.
Related questions
Как посчитать только верхний уровень? find . -maxdepth 1 -type f | wc -l не спускается в подпапки.
Как посчитать файлы одного типа? find . -type f -name '*.log' | wc -l. Регистр важен; если не нужен — -iname.
А если нужен объём, а не число? du -sh . даёт суммарный размер, du -h --max-depth=1 | sort -h — разбивку по подпапкам.
See also
CliAI превращает «сколько файлов по типам» в готовый конвейер и показывает его до запуска. Поставить одной строкой.