Wie zähle ich die Anzahl der Dateien in jedem Verzeichnis?

103

Ich kann alle Verzeichnisse von auflisten

find ./ -type d

Ich habe versucht, den Inhalt jedes Verzeichnisses aufzulisten und die Anzahl der Dateien in jedem Verzeichnis mit dem folgenden Befehl zu zählen

find ./ -type d | xargs ls -l | wc -l

Dies summierte jedoch die Gesamtzahl der zurückgegebenen Zeilen

find ./ -type d | xargs ls -l

Gibt es eine Möglichkeit, die Anzahl der Dateien in jedem Verzeichnis zu zählen?

user784637
quelle
Suchen Sie nach einer Möglichkeit, die Anzahl der Dateien in jedem der Unterverzeichnisse direkt unter zu zählen ./?
Tuxdude
5
Wie ist das eine Off-Topic-Frage? Ich würde gerne Kommentare von Wählern mit gutem Grund sehen! Wenn dies nicht zum Thema gehört, wo gehört es dann hin? Super User? Ich glaube nicht ..
InfantPro'Aravind '
5
Shell-Skript, Batch-Skript sind im Programmierbereich!
InfantPro'Aravind '
Ich wollte gerade eine pythonische Lösung veröffentlichen, dann bemerkte ich, dass die Frage geschlossen ist.
Anatoly Techtonik
stimmte für die Wiedereröffnung. Es kann andere Antworten geben, die in vielen Situationen nützlich sein können (einschließlich Skriptprogrammierung, weshalb ich diese Frage erreicht habe).
Lepe

Antworten:

109

Angenommen, Sie haben GNU gefunden, lassen Sie es die Verzeichnisse finden und lassen Sie bash den Rest erledigen:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done
Glenn Jackman
quelle
2
Es ist nur eine etwas andere Version als oben, also: (Hinweis: es ist nach Namen sortiert und in csv) für x in find . -maxdepth 1 -type d | sort; do y = find $x | wc -l; Echo $ x, $ y; erledigt
pcarvalho
5
Tolle Sache! Setzen Sie es in eine einzelne Zeile (so ist es bequem für die direkte Verwendung in der Shell):find . -type d -print0 | while read -d '' -r dir; do files=("$dir"/*); printf "%5d files in directory %s\n" "${#files[@]}" "$dir"; done
Lucaferrario
13
Ich musste die Anzahl aller Dateien (rekursiv zählen) in jedem Unterverzeichnis ermitteln. Diese Änderung gibt Ihnen find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find $dir -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
Folgendes
1
@Kory Folgendes wird es tun:find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done | sort -rn -k1
OmidS
1
@OmidS Großartiger Oneliner, $dirsollte aber in Ihrem ersten Kommentar in Anführungszeichen stehen, um Verzeichnisnamen mit Leerzeichen korrekt zu behandeln. :find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
Radek Daniluk
183

Dadurch wird die Anzahl der Dateien pro Verzeichnis für die aktuelle Verzeichnisebene gedruckt:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr
Sebastian Piskorski
quelle
9
Bei weitem die beste (und eleganteste) Lösung, wenn man die Anzahl der Dateien in Verzeichnissen der obersten Ebene rekursiv auflisten möchte.
Itoctopus
13
Dies hat zwei Probleme: Es zählt eine Datei pro Verzeichnis mehr als tatsächlich vorhanden und es wird eine unbrauchbare Zeile ausgegeben, die die Größe des aktuellen Verzeichnisses als "1 Größe " enthält. Beides kann mit behoben werden du -a | sed '/.*\.\/.*\/.*/!d' | cut -d/ -f2 | sort | uniq -c. Hinzufügen | sort -nr, um nach der Anzahl anstelle des Verzeichnisnamens zu sortieren.
Nachtisch
3
Ich möchte darauf hinweisen, dass dies auch unter OSX funktioniert. (Nur das Einfügen von Linux-Ratschlägen in eine OSX-Shell funktioniert normalerweise nicht.)
Pistos
2
es holt unnötige Größe von du -a. Besser ist die Verwendung des Befehls find. aber die Hauptidee ist genau die gleiche :)
Znik
5
finden . -Typ f | cut -d / -f2 | sortieren | uniq -c | sort -nr # behebt Probleme, die von Dessert erwähnt werden
jcomeau_ictx
26
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f um alle Elemente der Typdatei zu finden
  • cut -d/ -f2 um ihren spezifischen Ordner auszuschneiden
  • sort um die Liste der Ordnernamen zu sortieren
  • uniq -c um zurückzugeben, wie oft jeder Ordnername gezählt wurde
DCZ
quelle
6
Dies ist so viel besser als die akzeptierte Antwort, da Sie eine Zusammenfassung der Verzeichnisse der obersten Ebene erhalten!
Jason Floyd
2
Dies sollte die akzeptierte Antwort sein. Einfach und verständlich.
xssChauhan
1
Die beste Antwort, die akzeptiert werden sollte, ist diese.
Loretoparisi
1
Einfach, elegant und perfekt für meine Bedürfnisse.
RichR
Perfekt. Und kann erweitert werden, um über Unterverzeichnisse zu zählen, indem die Feldspezifizierer durch eine Liste von Feldspezifizierern ersetzt werden. ZB:find . -type f | cut -d/ -f2,3 | sort | uniq -c
Alge
15

Sie können veranlassen, alle Dateien zu finden, die Dateinamen zu entfernen, eine Zeile mit nur dem Verzeichnisnamen für jede Datei zu hinterlassen und dann zu zählen, wie oft jedes Verzeichnis angezeigt wird:

find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c

Das einzige Problem dabei ist, wenn Sie Dateinamen oder Verzeichnisnamen haben, die ein Zeilenumbruchzeichen enthalten, was ziemlich unwahrscheinlich ist. Wenn Sie sich wirklich Gedanken über Zeilenumbrüche in Dateinamen oder Verzeichnisnamen machen müssen, empfehlen wir Ihnen, diese zu finden und zu korrigieren, damit sie keine Zeilenumbrüche enthalten (und den Schuldigen leise vom Fehler ihres Weges zu überzeugen).


Wenn Sie an der Anzahl der Dateien in jedem Unterverzeichnis des aktuellen Verzeichnisses interessiert sind und alle Dateien in den Unterverzeichnissen zusammen mit den Dateien im unmittelbaren Unterverzeichnis zählen, würde ich den sedBefehl so anpassen , dass er nur gedruckt wird das Verzeichnis der obersten Ebene:

find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c

Das erste Muster erfasst den Anfang des Namens, den Punkt, den Schrägstrich, den Namen bis zum nächsten Schrägstrich und den Schrägstrich und ersetzt die Zeile nur durch den ersten Teil.

./dir1/dir2/file1

wird ersetzt durch

./dir1/

Beim zweiten Ersetzen werden die Dateien direkt im aktuellen Verzeichnis erfasst. Sie haben am Ende keinen Schrägstrich und diese werden durch ersetzt ./. Das Sortieren und Zählen funktioniert dann nur mit der Anzahl der Namen.

Jonathan Leffler
quelle
1
Dies gibt keine Verzeichnisnamen aus, die keine Dateien enthalten. Ich bin mir nicht sicher, ob dies erforderlich ist.
Austin Phillips
Das stimmt nicht. Es ist nicht besonders trivial, dies zu beheben, da nicht garantiert wird, dass die leeren Verzeichnisnamen auch nur in der Ausgabe von angezeigt werden find. Einige könnten: Wenn es eine Datei gibt dir1/dir2/dir3/file1, die aber dir1/dir2nur Unterverzeichnisse enthält (keine einfachen Dateien), können Sie auf deren Vorhandensein schließen. Wenn dir1/dir4jedoch keine Dateien vorhanden sind, wird der Name einfach nicht angezeigt.
Jonathan Leffler
Sehr nützliche Antwort, wenn Sie nur die Unterverzeichnisse des aktuellen Verzeichnisses anzeigen möchten.
Xixixao
Ich bin gerade vorbeigekommen, um mich zu bedanken. 3 Jahre nachdem dies veröffentlicht wurde, wollte ich Ordner der 2. Ebene pro Ordner zählen. Ihr Beitrag ersparte mir möglicherweise viele Stunden des Bastelns mit sed, find und wer weiß was noch
Corvin
13

Hier ist eine Möglichkeit, aber wahrscheinlich nicht die effizienteste.

find -type d -print0 | xargs -0 -n1 bash -c 'echo -n "$1:"; ls -1 "$1" | wc -l' --

Gibt eine Ausgabe wie folgt aus, mit Verzeichnisname gefolgt von der Anzahl der Einträge in diesem Verzeichnis. Beachten Sie, dass die Anzahl der Ausgaben auch Verzeichniseinträge enthält, die möglicherweise nicht Ihren Wünschen entsprechen.

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0
Austin Phillips
quelle
Es scheint sehr teuer 3 Befehle auszuführen ( bash, ls, wc) für jedes Verzeichnis gefunden find.
Jonathan Leffler
@ JonathanLeffler Einverstanden, daher die erste Zeile meiner Antwort. Ihre Lösung ist besser.
Austin Phillips
cool das ist was ich suche darf ich fragen was ist das '-' am ende?
Einmal
1
@once Das - gehört zum Befehl bash, der von xargs erzeugt wird. Von man bash, A -- signals the end of options and disables further option processing. In diesem Fall würde verhindert, dass eine als Teil des Funds gefundene falsch benannte Datei Teil der Argumentverarbeitung für bash wird.
Austin Phillips
8

Die Lösung aller anderen hat den einen oder anderen Nachteil.

find -type d -readable -exec sh -c 'printf "%s " "$1"; ls -1UA "$1" | wc -l' sh {} ';'

Erläuterung:

  • -type d: Wir interessieren uns für Verzeichnisse.
  • -readable: Wir wollen sie nur, wenn es möglich ist , die darin enthaltenen Dateien aufzulisten. Beachten Sie, dass findimmer noch ein Fehler ausgegeben wird, wenn versucht wird, nach weiteren Verzeichnissen in diesen zu suchen. Dies verhindert jedoch, dass diese aufgerufen -execwerden.
  • -exec sh -c BLAH sh {} ';': Führen Sie für jedes Verzeichnis dieses Skriptfragment mit $0set to shund $1set to the filename aus.
  • printf "%s " "$1": Geben Sie den Verzeichnisnamen portabel und minimal aus, gefolgt von einem Leerzeichen und keinem Zeilenumbruch.
  • ls -1UA: Listen Sie die Dateien, eine pro Zeile, in Verzeichnisreihenfolge auf (um ein Abwürgen der Pipe zu vermeiden), wobei nur die speziellen Verzeichnisse .und ausgeschlossen werden..
  • wc -l: Zähle die Zeilen
o11c
quelle
1
Änderung, um die Anzahl der Dateien zuerst in der Zeile find -type d -readable -exec sh -c 'ls -1UA "$1" | wc -l | tr -d "\n" ; printf "\t%s\n" "$1" ' sh {} ';' | sort -n
anzuzeigen
Es führt die Shell viele Male aus, ist dann langsam und nutzt Ressourcen in hohem Maße.
Znik
6

Leicht modifizierte Version von Sebastians Antwort mit findanstelle von du(um den Aufwand für die Dateigröße auszuschließen, der ausgeführt werden dumuss und der nie verwendet wird):

 find ./ -mindepth 2 -type f | cut -d/ -f2 | sort | uniq -c | sort -nr

-mindepth 2Der Parameter wird verwendet, um Dateien im aktuellen Verzeichnis auszuschließen. Wenn Sie es entfernen, sehen Sie eine Reihe von Zeilen wie die folgenden:

  234 dir1
  123 dir2
    1 file1
    1 file2
    1 file3
      ...
    1 fileN

(ähnlich wie die du-basierte Variante)

Wenn Sie die Dateien auch im aktuellen Verzeichnis zählen müssen, verwenden Sie diese erweiterte Version:

{ find ./ -mindepth 2 -type f | cut -d/ -f2 | sort && find ./ -maxdepth 1 -type f | cut -d/ -f1; } | uniq -c | sort -nr

Die Ausgabe sieht wie folgt aus:

  234 dir1
  123 dir2
   42 .
Yoory N.
quelle
5

Dies kann auch durch Schleifen über ls anstelle von find erfolgen

for f in */; do echo "$f -> $(ls $f | wc -l)"; done

Erläuterung:

for f in */; - Schleife über alle Verzeichnisse

do echo "$f -> - Drucken Sie jeden Verzeichnisnamen aus

$(ls $f | wc -l) - Rufen Sie ls für dieses Verzeichnis auf und zählen Sie die Zeilen

Sixhobbits
quelle
1
Dies funktioniert nicht richtig, wenn die Verzeichnisnamen Leerzeichen enthalten.
Xylol
Versuchen Siefor f ./* ; do echo $f $(ls "$f" | wc -l); done
4ndt3s
3

Dies sollte den Verzeichnisnamen gefolgt von der Anzahl der Dateien im Verzeichnis zurückgeben.

findfiles() {
    echo "$1" $(find "$1" -maxdepth 1 -type f | wc -l)
}

export -f findfiles

find ./ -type d -exec bash -c 'findfiles "$0"' {} \;

Beispielausgabe:

./ 6
./foo 1
./foo/bar 2
./foo/bar/bazzz 0
./foo/bar/baz 4
./src 4

Dies export -fist erforderlich, da das -execArgument von finddie Ausführung einer Bash-Funktion nur erlaubt, wenn Sie Bash explizit aufrufen und die im aktuellen Bereich definierte Funktion explizit in die neue Shell exportieren müssen.

Tuxdude
quelle
Dies scheint übermäßig kompliziert. Es sieht für mich auch so aus, als würde es kumulative Zählungen für eine Verzeichnishierarchie geben, z. B. ./dir1/dir2/dir3(Zählen der Dateien in dir1und ihrer Unterverzeichnisse zusammen, anstatt die Dateien dir1/dir2/dir3getrennt von denen in dir1/dir2und beide getrennt von denen in zu zählen /dir1).
Jonathan Leffler
Ich habe verstanden, dass der Autor das wollte. Wenn dies nicht der Fall ist, stimme ich zu, dass die Antwort für die Frage nicht relevant ist.
Tuxdude
1
@ JonathanLeffler - Okay, als ich die Frage noch einmal las, wurde mir klar, dass Sie Recht haben - ich habe die Antwort entsprechend geändert.
Tuxdude
1

finden . -Typ f -printf '% h \ n' | sortieren | uniq -c

gibt zum Beispiel:

  5 .
  4 ./aln
  5 ./aln/iq
  4 ./bs
  4 ./ft
  6 ./hot
Schwindlig
quelle
1

Ich habe die Antwort von @glenn jackman und die Antwort von @ pcarvalho kombiniert (in der Kommentarliste stimmt etwas mit der Antwort von pcarvalho nicht, weil die zusätzliche Stilsteuerungsfunktion des Zeichens ' ` ' (Backtick)).

Mein Skript kann den Pfad als Erweiterung akzeptieren und die Verzeichnisliste nach sortieren. ls -lAußerdem kann es das Problem des "Speicherplatzes im Dateinamen" behandeln .

#!/bin/bash
OLD_IFS="$IFS"
IFS=$'\n'
for dir in $(find $1 -maxdepth 1 -type d | sort); 
do
    files=("$dir"/*)
    printf "%5d,%s\n" "${#files[@]}" "$dir"
done
FS="$OLD_IFS"

Meine erste Antwort in Stackoverflow, und ich hoffe, es kann jemandem helfen ^ _ ^

räumen
quelle
0

Ich habe es mit einigen der anderen hier versucht, aber am Ende waren Unterordner in der Anzahl der Dateien enthalten, als ich nur die Dateien haben wollte. Dies wird ./folder/path<tab>nnnmit der Anzahl der Dateien ohne Unterordner für jeden Unterordner im aktuellen Ordner gedruckt.

for d in `find . -type d -print` 
do 
  echo -e "$d\t$(find $d -maxdepth 1 -type f -print | wc -l)"
done
sthames42
quelle
0

Einfache Möglichkeit, Dateien eines bestimmten Typs rekursiv zu finden. In diesem Fall JPG-Dateien für alle Ordner im aktuellen Verzeichnis:

find . -name *.jpg -print | wc -l

Rex Barker
quelle
0

Ein superschneller Wunderbefehl, der Dateien rekursiv durchläuft, um die Anzahl der Bilder in einem Verzeichnis zu zählen und die Ausgabe nach Bilderweiterung zu organisieren:

find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'

Credits: https://unix.stackexchange.com/a/386135/354980

tsveti_iko
quelle
0

Dies könnte eine andere Möglichkeit sein, die Verzeichnisstrukturen zu durchsuchen und Tiefenergebnisse zu liefern.

find . -type d  | awk '{print "echo -n \""$0"  \";ls -l "$0" | grep -v total | wc -l" }' | sh 
Joseph Earnest
quelle
-1

Dies ergibt die Gesamtzahl.

for file in */; do echo "$file -> $(ls $file | wc -l)"; done | cut -d ' ' -f 3| py --ji -l 'numpy.sum(l)'
Naga Venkatesh Gavini
quelle
Nein es wird nicht. Es wird nur eine Ebene von Unterverzeichnissen berücksichtigt.
Kusalananda