Почему делает '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

Каково объяснение?

29
задан 10 October 2017 в 11:11

2 ответа

The 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
37
ответ дан 23 November 2019 в 01:12

user4556274 уже ответил на почему. Мой ответ служит только для того, чтобы предоставить дополнительную информацию для как правильно считать файлы.

В сообществе Unix общее мнение заключается в том, что парсинг вывода ls является очень плохой идеей , так как имена файлов могут содержать управляющие или скрытые символы. Например, из-за символа новой строки в имени файла, мы имеем ls | wc -l говорят нам, что в выводе ls есть 5 строк (которые у него есть), но на самом деле в каталоге только 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 : globstar

Простой, быстрый и в основном портативный способ:

$ set -- * 
$ echo $#
228

set используется для установки позиционных параметров оболочки ( переменные $, как в echo $1). Это часто используется для работы вокруг /bin/sh ограничения недостающих массивов. Версию, которая выполняет дополнительные проверки, можно найти в ответе Gille на Unix&Linux.

В оболочках, которые поддерживают массивы, такие как bash, мы можем использовать

items=( dir/* )
echo ${#items[@]}

, как предлагает steeldriver в комментариях .

Аналогично методу find, который использовал wc и globstar, можно использовать с stat для подсчета номеров кодов на строку:

$> LC_ALL=C stat ./* --printf "%i\n" | wc -l                                          
4

Альтернативным подходом является использование спецсимвола в для петли . (Обратите внимание, этот тест использует другой каталог для проверки, не попадает ли этот подход в подкаталоги, чего он не делает - 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

См. также

18
ответ дан 23 November 2019 в 01:12

Другие вопросы по тегам:

Похожие вопросы: