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потерпит неудачу, если есть файлы с новой строкой в имени файла. Это более устойчиво:find . -mindepth 1 -maxdepth 1 -printf . | wc -c
Flimm
20
«если в именах файлов есть новая строка» ... дрожь
Петах
8
Как man lsвам скажут, вы можете избежать контрольных символов с -b(избегает их) или -q(опускает их). Таким образом, для подсчета, ls -1q | wc -lявляется безопасным и точным для отображения не скрытых файлов. ls -1qA | wc -lсчитать скрытые файлы (но не .а ..). Я использую -1вместо, -lпотому что это должно быть быстрее.
Оли
18
Пользователь 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для предотвращения рекурсивного спуска в подкаталоги)
setКоманда используется для установки позиционных параметров оболочки ( $<INTEGER>переменных, как в echo $1). Это часто используется, чтобы обойти /bin/shограничение отсутствия массивов. Версия, которая выполняет дополнительные проверки, может быть найдена в ответе Джилла на Unix & Linux.
В оболочках, которые поддерживают массивы, такие как bash, мы можем использовать
Аналогично 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
В bash другим вариантом будет использование массива, например items=( dir/* ); echo ${#items[@]}(добавление shopt -s dotglobдля включения скрытых файлов).
SteelDriver
1
Печать номеров узлов позволяет легко фильтровать жесткие ссылки, если это необходимо, с помощью find | sort -u | wc -l.
Питер Кордес
@steeldriver: я думаю, что метод bash-array вряд ли будет быстрее. Если вы хотите, чтобы он был рекурсивным, вам нужно использовать items=( dir/** )(с shopt -s globstar), но bash не использует дополнительные метаданные из readdir, поэтому он регистрирует каждую запись каталога, чтобы увидеть, является ли она самой директорией. Многие файловые системы хранят тип файла в записи каталога, поэтому readdir может вернуть его, не обращаясь к inode. (Например, последняя версия XFS, отличная от используемой по умолчанию, имеет это, и я думаю, что в ext4 она была дольше.) Если вы straceобнаружите, вы увидите намного меньше statсистемных вызовов, чем в bash.
Питер Кордес
2
Почему бы просто не использовать print(len(os.listdir('.')))? Меньше символов для ввода, а также избегает доступа к атрибутам с двойной подчеркиванием.
ls | wc -l
потерпит неудачу, если есть файлы с новой строкой в имени файла. Это более устойчиво:find . -mindepth 1 -maxdepth 1 -printf . | wc -c
man ls
вам скажут, вы можете избежать контрольных символов с-b
(избегает их) или-q
(опускает их). Таким образом, для подсчета,ls -1q | wc -l
является безопасным и точным для отображения не скрытых файлов.ls -1qA | wc -l
считать скрытые файлы (но не.
а..
). Я использую-1
вместо,-l
потому что это должно быть быстрее.Пользователь 4556274 уже ответил на вопрос « почему» . Мой ответ служит только для предоставления дополнительной информации о том, как правильно считать файлы.
В сообществе Unix общий консенсус заключается в том, что синтаксический анализ выходных данных
ls
является очень плохой идеей , поскольку имена файлов могут содержать управляющие символы или скрытые символы. Например, из-за символа новой строки в имени файла мыls | wc -l
сказали, что в выводе есть 5 строкls
(которые есть), но на самом деле в каталоге только 4 файла.Способ № 1: найти утилиту
Команда
find
, которая обычно используется для работы с синтаксическим анализом имен файлов, может помочь нам, напечатав номер инода . Будь то каталог или файл, он имеет только один уникальный номер inode. Таким образом, используя-printf "%i\n"
и исключая.
через,-not -name "."
мы можем иметь точное количество файлов. (Обратите внимание на использование-maxdepth 1
для предотвращения рекурсивного спуска в подкаталоги)Способ № 2: глобстар
Простой, быстрый и в основном портативный способ:
set
Команда используется для установки позиционных параметров оболочки ($<INTEGER>
переменных, как вecho $1
). Это часто используется, чтобы обойти/bin/sh
ограничение отсутствия массивов. Версия, которая выполняет дополнительные проверки, может быть найдена в ответе Джилла на Unix & Linux.В оболочках, которые поддерживают массивы, такие как
bash
, мы можем использоватькак предложено Steeldriver в комментариях .
Аналогично
find
методу, который использовался,wc
и globstar можно использоватьstat
для подсчета номеров инодов в строке:Альтернативный подход заключается в использовании подстановочного знака в
for
цикле. (Обратите внимание, что в этом тесте используется другой каталог для проверки, подходит ли этот подход к подкаталогам, чего нет - 16 - это проверенное количество элементов в моем~/bin
)Метод № 3: другие языки / переводчики
Python также может иметь дело с проблемными именами файлов путем печати длины списка с учетом моей
os.listdir()
функции (которая не является рекурсивной и будет перечислять только элементы в каталоге, указанном в качестве аргумента).Смотрите также
источник
items=( dir/* ); echo ${#items[@]}
(добавлениеshopt -s dotglob
для включения скрытых файлов).find | sort -u | wc -l
.items=( dir/** )
(сshopt -s globstar
), но bash не использует дополнительные метаданные из readdir, поэтому он регистрирует каждую запись каталога, чтобы увидеть, является ли она самой директорией. Многие файловые системы хранят тип файла в записи каталога, поэтому readdir может вернуть его, не обращаясь к inode. (Например, последняя версия XFS, отличная от используемой по умолчанию, имеет это, и я думаю, что в ext4 она была дольше.) Если выstrace
обнаружите, вы увидите намного меньшеstat
системных вызовов, чем в bash.print(len(os.listdir('.')))
? Меньше символов для ввода, а также избегает доступа к атрибутам с двойной подчеркиванием.