Почему `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