Почему `ls -l` считает больше файлов, чем я?
Видимо я не могу сосчитать. Я думаю, что есть три файла в /media
$ tree /media
/media
├── foo
├── onex
└── zanna
3 directories, 0 files
Тем не мение, ls -l находит 12.
$ ls -l /media
total 12
drwxr-xr-x 2 root root 4096 Jul 31 20:57 foo
drwxrwxr-x 2 root root 4096 Jun 26 06:36 onex
drwxr-x---+ 2 root root 4096 Aug 7 21:17 zanna
И если я сделаю ls -la Я получаю только . а также .. в дополнение к вышесказанному, но количество total 20
Какое объяснение?
2 ответа
12 вы видите не количество файлов, а количество использованных дисковых блоков.
От info coreutils 'ls invocation':
For each directory that is listed, preface the files with a line
`total BLOCKS', where BLOCKS is the total disk allocation for all
files in that directory. The block size currently defaults to 1024
bytes, but this can be overridden (*note Block size::). The
BLOCKS computed counts each hard link separately; this is arguably
a deficiency.
Всего идет от 12 в 20 когда вы используете ls -la вместо ls -l потому что вы считаете две дополнительные директории: . а также .., Вы используете четыре дисковых блока для каждого (пустого) каталога, поэтому ваше общее количество увеличивается с 3 × 4 до 5 × 4. (По всей вероятности, вы используете один дисковый блок размером 4096 байт для каждого каталога; info страница указывает, что утилита не проверяет формат диска, но предполагает размер блока 1024 если не указано иное.)
Если вы хотите просто получить количество файлов, вы можете попробовать что-то вроде
ls | wc -l
Пользователь user4556274 уже ответил на вопрос " почему". Мой ответ служит только для предоставления дополнительной информации о том, как правильно считать файлы.
В сообществе 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