Pourquoi ls -l compte-t-il plus de fichiers que moi?

24

Apparemment, je ne peux pas compter. Je pense qu'il y a trois fichiers dans /media

$ tree /media
/media
├── foo
├── onex
└── zanna
3 directories, 0 files

Cependant, ls -l trouve 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

Et si je fais ls -la , je n'ai que . et .. en plus de ce qui précède, mais le nombre est de total 20

Quelle est l'explication?

    
posée Zanna 10.08.2016 - 16:44
la source

2 réponses

32

Le 12 que vous voyez n'est pas le nombre de fichiers, mais le nombre de blocs de disque consommés.

De 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.

Le total va de 12 à 20 lorsque vous utilisez ls -la au lieu de ls -l car vous comptez deux répertoires supplémentaires: . et .. . Vous utilisez quatre blocs de disque pour chaque répertoire (vide), de sorte que votre total passe de 3 × 4 à 5 × 4. Vous utilisez probablement un bloc de disque de 4096 octets pour chaque répertoire. Comme l'indique la page info , l'utilitaire ne vérifie pas le format du disque, mais suppose une taille de bloc de 1024 sauf instruction contraire.)

Si vous voulez simplement obtenir le nombre de fichiers, vous pouvez essayer quelque chose comme

ls | wc -l
    
réponse donnée user4556274 10.08.2016 - 16:49
la source
18

user4556274 a déjà répondu à la raison pour laquelle . Ma réponse sert uniquement à fournir des informations supplémentaires sur la manière dont comment comptabiliser correctement les fichiers.

Dans la communauté Unix, le consensus général est que l'analyse de la sortie de ls est une très mauvaise idée, car les noms de fichiers peuvent contenir des caractères de contrôle ou des caractères cachés. Par exemple, à cause d'un caractère de nouvelle ligne dans un nom de fichier, ls | wc -l nous dit qu'il y a 5 lignes dans la sortie de ls (ce qu'il a), mais en réalité il n'y a que 4 fichiers dans le répertoire.

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

La commande find , généralement utilisée pour contourner les noms de fichiers, peut nous aider en imprimant le numéro d’inode . Qu'il s'agisse d'un répertoire ou d'un fichier, il n'a qu'un seul numéro d'inode. Ainsi, en utilisant -printf "%i\n" et en excluant . via -not -name "." , nous pouvons avoir un décompte précis des fichiers. (Notez l'utilisation de -maxdepth 1 pour empêcher la descente récursive dans les sous-répertoires)

$> 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

La même astuce peut être utilisée avec stat pour compter les nombres d'inodes par ligne:

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

Une autre approche consiste à utiliser un caractère générique. (Remarque: ce test utilise un répertoire différent pour vérifier si cette approche descend dans des sous-répertoires, ce qui n'est pas le cas - 16 correspond au nombre d'éléments vérifiés dans mon ~/bin ).

$> count=0; for item in ~/bin/* ; do count=$(($count+1)) ; echo $count ; done | tail -n 1                                
16

Python peut également gérer les noms de fichiers problématiques en imprimant la longueur d’une liste en fonction de ma fonction os.listdir() (qui n’est pas récursive et ne listera que les éléments du répertoire en argument).

$> python -c "import os ; print os.listdir('.')"                              
['file2.txt', 'file1.txt', 'FILE\nNAME', 'file3.txt']
$>  python -c "import os ; print(len(os.listdir('.')))"                    
4
    
réponse donnée Sergiy Kolodyazhnyy 10.08.2016 - 22:51
la source

Lire d'autres questions sur les étiquettes