ИТ Блог. Администрирование серверов на основе Linux (Ubuntu, Debian, CentOS, openSUSE)

Наилучший способ подсчета файлов в каталоге?

Наилучший способ подсчета файлов в каталоге?

Существует несколько способов подсчета количества файлов в каталоге в Linux. Некоторые из них менее надежны, чем другие, и могут даже привести к неточному подсчету файлов. В этом посте рассматриваются подводные камни и рекомендации для трех различных подходов с использованием ls, find и bash оболочки, использующей глобализацию и массив bash.

 

Как подсчитать файлы с помощью команд ls и wc?

Большинство решений, которые вы найдете в Интернете, будут пытаться проанализировать вывод команды 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 с 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?

Вам не нужно использовать другие инструменты командной строки для подсчета количества файлов в каталоге в bash. Вместо предыдущих решений, без дополнительной fork(), вы можете использовать bash globbing с опциями nullglob и dotglob с массивом bash и, необязательно, оператором if в bash.

  • Параметр nullglob расширится до нулевой строки (пустое значение), если ни один файл не соответствует шаблонам имен файлов.
  • Опция dotglob используется также для перечисления скрытых файлов, начинающихся с точки (.). Вы можете пропустить этот параметр, если хотите подсчитывать только файлы, которые не начинаются с точки.

 

Обязательно установите (с помощью 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
Exit mobile version