Warum zählt ls -l mehr Dateien als ich?


25

Anscheinend kann ich nicht zählen. Ich denke, es gibt drei Dateien in/media

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

Allerdings ls -lfindet 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

Und wenn ich das tue, ls -labekomme ich nur .und ..zusätzlich das oben Genannte, aber die Zählung isttotal 20

Was ist die Erklärung?

Antworten:


33

Die 12Sie sehen , ist nicht die Anzahl der Dateien, aber die Anzahl der Plattenblöcke verbraucht.

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

Die Summe geht von 12bis, 20wenn Sie ls -laanstelle von verwenden, ls -lweil Sie zwei zusätzliche Verzeichnisse zählen: .und ... Sie verwenden vier Plattenblöcke für jedes (leere) Verzeichnis, sodass Ihre Gesamtzahl von 3 × 4 auf 5 × 4 steigt. (Höchstwahrscheinlich verwenden Sie einen Plattenblock von 4096 Bytes für jedes Verzeichnis, wie die infoSeite zeigt, die Dienstprogramm überprüft das Festplattenformat nicht, geht jedoch von einer Blockgröße von aus, 1024sofern nicht anders angegeben.)

Wenn Sie einfach die Anzahl der Dateien abrufen möchten, können Sie etwas wie versuchen

ls | wc -l

13
ls | wc -lschlägt fehl, wenn der Dateiname Dateien mit einer neuen Zeile enthält. Dies ist widerstandsfähiger:find . -mindepth 1 -maxdepth 1 -printf . | wc -c
Flimm

20
"Wenn Dateinamen eine neue Zeile enthalten" ... schaudert
Petah

8
Wie man lsSie sehen, können Sie Steuerzeichen vermeiden, indem Sie -b(sie maskieren) oder -q(sie weglassen). So zum Zählen, ls -1q | wc -list sicher und genau zum Anzeigen von nicht versteckten Dateien. ls -1qA | wc -lversteckte Dateien zu zählen (aber nicht .und ..). Ich benutze -1stattdessen, -lweil das schneller sein sollte.
Oli

18

user4556274 hat das warum bereits beantwortet . Meine Antwort dient nur dazu, zusätzliche Informationen darüber, wie richtig Dateien zählen zu.

In der Unix-Community herrschtls allgemeiner Konsens darüber, dass das Parsen der Ausgabe eine sehr, sehr schlechte Idee ist , da Dateinamen Steuerzeichen oder versteckte Zeichen enthalten können. Aufgrund eines Zeilenumbruchs in einem Dateinamen müssen wir uns beispielsweise ls | wc -lmitteilen, dass die Ausgabe von 5 Zeilen enthält ls(was auch der Fall ist), in Wirklichkeit befinden sich jedoch nur 4 Dateien im Verzeichnis.

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

Methode 1: finden Sie Dienstprogramm

Der findBefehl, der normalerweise zum Analysieren von Dateinamen verwendet wird, kann uns hier helfen, indem er die Inode-Nummer ausgibt . Sei es ein Verzeichnis oder eine Datei, es hat nur eine einzige Inode-Nummer. Durch die Verwendung -printf "%i\n"und den Ausschluss von .via können -not -name "."wir die Dateien genau zählen. (Beachten Sie die Verwendung von -maxdepth 1, um ein rekursives Absteigen in Unterverzeichnisse zu verhindern.)

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

Methode 2: Globstar

Einfach, schnell und meistens portabel:

$ set -- * 
$ echo $#
228

setBefehl wird verwendet, um Positionsparameter der Shell festzulegen (die $<INTEGER>Variablen, wie in echo $1). Dies wird häufig verwendet, um die /bin/shBegrenzung fehlender Arrays zu umgehen. Eine Version, die zusätzliche Prüfungen durchführt, finden Sie in Gilles Antwort unter Unix & Linux.

In Shells, die Arrays unterstützen, wie bashwir sie verwenden können

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

wie von steeldriver in den Kommentaren vorgeschlagen .

Ein ähnlicher Trick wie bei der findMethode "which used" wcund "globstar" kann statzum Zählen der Inode-Nummern pro Zeile verwendet werden:

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

Ein alternativer Ansatz ist die Verwendung eines Platzhalters in einer forSchleife. (Beachten Sie, dass dieser Test ein anderes Verzeichnis verwendet, um zu testen, ob dieser Ansatz in Unterverzeichnisse abfällt, was nicht der Fall ist. 16 ist die überprüfte Anzahl von Elementen in my. ~/bin)

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

Methode 3: Andere Sprachen / Dolmetscher

Python kann auch mit problematischen Dateinamen umgehen, indem es die Länge einer Liste in Anbetracht meiner os.listdir()Funktion ausgibt (was nicht rekursiv ist und nur Elemente in dem als Argument angegebenen Verzeichnis auflistet).

$> python -c "import os ; print os.listdir('.')"                              
['file2.txt', 'file1.txt', 'FILE\nNAME', 'file3.txt']
$>  python -c "import os ; print(len(os.listdir('.')))"                    
4

Siehe auch


2
In Bash wäre eine andere Option, ein Array zu verwenden, z. B. items=( dir/* ); echo ${#items[@]}(Hinzufügen shopt -s dotglob, um versteckte Dateien einzuschließen).
Steeldriver

1
Das Drucken von Inode-Nummern erleichtert das Filtern von Hardlinks, falls gewünscht, mit find | sort -u | wc -l.
Peter Cordes

@steeldriver: Ich denke, dass die Bash-Array-Methode wahrscheinlich nicht schneller ist. Wenn Sie möchten, dass es rekursiv ist, müssen Sie items=( dir/** )(with shopt -s globstar) verwenden, aber bash nutzt keine zusätzlichen Metadaten aus readdir aus, sodass in jedem Verzeichniseintrag angegeben wird, ob es sich um ein Verzeichnis selbst handelt. Viele Dateisysteme speichern den Dateityp im Verzeichniseintrag, sodass readdir ihn zurückgeben kann, ohne auf die Inodes zuzugreifen. (ZB hat dies das neueste nicht standardmäßige XFS, und ich denke, ext4 hat es länger.) Wenn Sie stracefeststellen, werden Sie viel weniger statSystemaufrufe sehen als wenn Sie bash stracen.
Peter Cordes

2
Warum nicht einfach benutzen print(len(os.listdir('.')))? Es müssen weniger Zeichen eingegeben werden, und der Zugriff auf doppelt unterstrichene Attribute wird vermieden.
Edwinksl

1
@edwinksl bearbeitet, thx
Sergiy Kolodyazhnyy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.