Существует несколько способов подсчета количества файлов в каталоге в Linux. Некоторые из них менее надежны, чем другие, и могут даже привести к неточному подсчету файлов. В этом посте рассматриваются подводные камни и рекомендации для трех различных подходов с использованием ls, find и bash оболочки, использующей глобализацию и массив bash.
Большинство решений, которые вы найдете в Интернете, будут пытаться проанализировать вывод команды ls, который передается через wc командную строку, иногда добавляя grep в микс. Распространенным примером является ls -la | wc -l. Этот подход ненадежен, и его следует избегать.
Помимо двух разветвленных процессов для ls и wc, ls выходные данные никогда не следует анализировать, поскольку имя файла может содержать символ новой строки, что приведет к плохим результатам при использовании ls и wc. В этом примере подсчет также будет неверным, поскольку он будет включать ссылки на . (текущий каталог) и .. (родительский каталог).
Лучшей версией было бы использовать, ls -1bA | wc -l которая пропускала бы . и .. из ls выходных данных, исключала непечатаемые символы и заставляла выводить по одной записи в строке.
[andreyex@linux ~]$ ls -a tmp/ . .. .one file1 file2 [andreyex@linux ~]$ ls -a tmp/ | wc -l 5 [andreyex@linux ~]$ ls -1bA tmp/* tmp/.one tmp/file1 tmp/file2 [andreyex@linux ~]$ ls -1bA | wc -l 3
Другое решение, аналогичное предыдущему, заключается в использовании find с wc, например: find tmp/ -type f | wc -l.
Этот подход будет иметь ту же ошибку, что и ls, поскольку имена файлов могут содержать непечатаемые символы, включая новые строки. Выходные данные могут быть ненадежно проанализированы. Чтобы преодолеть это, мы можем использовать команду printf утилиты GNU find utility. Обратите внимание, что это не стандартная опция POSIX.
С помощью printf мы можем пропустить вывод имени файла и заменить его точкой (или любым другим одиночным символом) для каждого найденного файла, а затем подсчитывать только общее количество символов, используя wc -c, например: find tmp -type f -printf ‘.’ | wc -c.
👉 Чтобы установить GNU Find на macOS, вы можете использовать менеджер пакетов homebrew с командой brew install findutils. Команда find будет установлена как gfind по умолчанию.
[andreyex@linux ~]$ find tmp -type f tmp/file2 tmp/file1 tmp/.one [andreyex@linux ~]$ find tmp -type f | wc -l 3 [andreyex@linux ~]$ find tmp -type f -printf '.' ... [andreyex@linux ~]$ find tmp -type f -printf '.' | wc -c 3
Вам не нужно использовать другие инструменты командной строки для подсчета количества файлов в каталоге в bash. Вместо предыдущих решений, без дополнительной fork(), вы можете использовать bash globbing с опциями nullglob и dotglob с массивом bash и, необязательно, оператором if в bash.
Обязательно установите (с помощью shopt -s nullglob dotglob) и отмените (с помощью shopt -u nullglob dotglob) параметры до и после тестирования, поскольку это может повлиять на остальную часть поведения вашего скрипта, особенно с опцией nullglob.
[andreyex@linux ~]$ shopt -s nullglob dotglob [andreyex@linux ~]$ matched_files=(tmp/*) [andreyex@linux ~]$ if ! (( ${#matched_files[*]} )); then echo "Каталог пуст" else echo "Каталог содержит ${#matched_files[@]} элемента, которые включают файлы, символическую ссылку, каталоги и т.д." fi # Пример вывода: Каталог содержит 3 элемента, которые включают файлы, символическую ссылку, каталоги и т.д. [andreyex@linux ~]$ shopt -u nullglob dotglob
При желании вы можете установить shopt в подоболочке, чтобы гарантировать, что остальная часть вашего скрипта не пострадает, за счет дополнительной вилки(). Ниже приведен пример с подоболочкой bash, чтобы проверить, пуст ли каталог. Помните, что вы не можете получить доступ к переменным, определенным в подоболочке, поэтому варианты использования могут быть ограниченными или менее читаемыми.
[andreyex@linux ~]$ if (shopt -s nullglob dotglob; files=(tmp/*); ((${#files[@]}))); then echo "Каталог не пуст"; fi