Пользователь 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