Почему `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, я получаю только [ f6] и .. в дополнение к вышесказанному, но счет total 20

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

1
задан 10 October 2017 в 21:11

1 ответ

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

В сообществе Unix общий консенсус заключается в том, что синтаксический анализ вывода ls - очень плохая идея, поскольку имена файлов могут содержать контроль символов или скрытых символов. Например, из-за символа новой строки в имени файла мы ls | wc -l сообщают, что на выходе ls (что у него есть) есть 5 строк, но на самом деле в каталоге есть только 4 файла. [!d3 ]

$> touch  FILE$'\n'NAME                                                       
$> ls                                                                         
file1.txt  file2.txt  file3.txt  FILE?NAME
$> ls | wc -l
5

Команда find, которая обычно используется для работы с парсингом имен файлов, может помочь нам здесь, напечатав номер inode. Будь то каталог или файл, он имеет только один уникальный номер 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

То же самое можно использовать с 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

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 May 2018 в 07:16
  • 1
    В bash другой вариант заключается в использовании массива, например. items=( dir/* ); echo ${#items[@]} (добавление shopt -s dotglob для включения скрытых файлов). – steeldriver 11 August 2016 в 07:01
  • 2
    Печать номеров индексных номеров упрощает фильтрацию жестких ссылок, если необходимо, с помощью find | sort -u | wc -l. – Peter Cordes 11 August 2016 в 07:06
  • 3
    @steeldriver: Я думаю, что метод bash-array вряд ли будет быстрее. Если вы хотите, чтобы он был рекурсивным, вам нужно использовать items=( dir/** ) (с shopt -s globstar), но bash не использует лишние метаданные из readdir, поэтому он определяет каждую запись в каталоге, чтобы узнать, является ли это самой папкой. Многие файловые системы сохраняют тип файла в записи каталога, поэтому readdir может возвращать его без доступа к inodes. (например, в последней версии XFS, отличной от используемой по умолчанию, и я думаю, что ext4 имеет ее дольше.) Если вы найдете strace, вы увидите гораздо меньше stat системных вызовов, чем stracing bash. – Peter Cordes 11 August 2016 в 07:11
  • 4
    Почему бы просто не использовать print(len(os.listdir('.')))? Меньшее количество символов для ввода, а также избегает доступа к двунаправленным атрибутам. – edwinksl 11 August 2016 в 08:05
  • 5
    @edwinksl отредактировал thx – Sergiy Kolodyazhnyy 11 August 2016 в 08:46

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

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