Пользователь 4556274 уже ответил на вопрос « почему» . Мой ответ служит только для предоставления дополнительной информации о том, как правильно считать файлы.
В сообществе Unix общий консенсус заключается в том, что синтаксический анализ выходных данных lsявляется очень плохой идеей , поскольку имена файлов могут содержать управляющие символы или скрытые символы. Например, из-за символа новой строки в имени файла мы ls | wc -lсказали, что в выводе есть 5 строк ls(которые есть), но на самом деле в каталоге только 4 файла.
$> touch FILE$'\n'NAME
$> ls
file1.txt file2.txt file3.txt FILE?NAME
$> ls | wc -l
5
Способ № 1: найти утилиту
Команда find, которая обычно используется для работы с синтаксическим анализом имен файлов, может помочь нам, напечатав номер инода . Будь то каталог или файл, он имеет только один уникальный номер inode. Таким образом, используя -printf "%i\n"и исключая .через, -not -name "."мы можем иметь точное количество файлов. (Обратите внимание на использование -maxdepth 1для предотвращения рекурсивного спуска в подкаталоги)
$> find -maxdepth 1 -not -name "." -print
./file2.txt
./file1.txt
./FILE?NAME
./file3.txt
$> find -maxdepth 1 -not -name "." -printf "%i\n" | wc -l
4
Способ № 2: глобстар
Простой, быстрый и в основном портативный способ:
$ set -- *
$ echo $#
228
setКоманда используется для установки позиционных параметров оболочки ( $<INTEGER>переменных, как в echo $1). Это часто используется, чтобы обойти /bin/shограничение отсутствия массивов. Версия, которая выполняет дополнительные проверки, может быть найдена в ответе Джилла на Unix & Linux.
В оболочках, которые поддерживают массивы, такие как bash, мы можем использовать
items=( dir/* )
echo ${#items[@]}
как предложено Steeldriver в комментариях .
Аналогично findметоду, который использовался, wcи globstar можно использовать statдля подсчета номеров инодов в строке:
$> LC_ALL=C stat ./* --printf "%i\n" | wc -l
4
Альтернативный подход заключается в использовании подстановочного знака в forцикле. (Обратите внимание, что в этом тесте используется другой каталог для проверки, подходит ли этот подход к подкаталогам, чего нет - 16 - это проверенное количество элементов в моем ~/bin)
$> count=0; for item in ~/bin/* ; do count=$(($count+1)) ; echo $count ; done | tail -n 1
16
Метод № 3: другие языки / переводчики
Python также может иметь дело с проблемными именами файлов путем печати длины списка с учетом моей os.listdir()функции (которая не является рекурсивной и будет перечислять только элементы в каталоге, указанном в качестве аргумента).
$> python -c "import os ; print os.listdir('.')"
['file2.txt', 'file1.txt', 'FILE\nNAME', 'file3.txt']
$> python -c "import os ; print(len(os.listdir('.')))"
4
Смотрите также
ls | wc -lпотерпит неудачу, если есть файлы с новой строкой в имени файла. Это более устойчиво:find . -mindepth 1 -maxdepth 1 -printf . | wc -c