Was ist der beste Weg, um "Find" -Ergebnisse zu zählen?

95

Meine derzeitige Lösung wäre find <expr> -exec printf '.' \; | wc -c, aber dies dauert viel zu lange, wenn mehr als 10000 Ergebnisse vorliegen. Gibt es keinen schnelleren / besseren Weg, dies zu tun?

MechMK1
quelle
Verwenden Sie wc -l für Ihre Suchergebnisse
Manuel Selva

Antworten:

81

Versuchen Sie stattdessen (erfordern find‚s - -printfUnterstützung):

find <expr> -type f -printf '.' | wc -c

Es ist zuverlässiger und schneller als das Zählen der Zeilen.

Beachten Sie, dass ich die find's verwende printf, keinen externen Befehl.


Lassen Sie uns ein wenig auf die Bank setzen:

$ ls -1
a
e
l
ll.sh
r
t
y
z

Mein Snippet-Benchmark:

$ time find -type f -printf '.' | wc -c
8

real    0m0.004s
user    0m0.000s
sys     0m0.007s

Mit vollen Zeilen:

$ time find -type f | wc -l
8

real    0m0.006s
user    0m0.003s
sys     0m0.000s

Meine Lösung ist also schneller =) (der wichtige Teil ist die realLinie)

Gilles Quenot
quelle
6
Nicht gleichwertig, es ist zuverlässiger =)
Gilles Quenot
6
Es ist nicht zuverlässiger, wenn das zu findende Flag -printf auf Ihrer Plattform nicht unterstützt wird. ;-)
Randy Howard
7
Beachten Sie, dass Sie einige weitere Nanosekunden sparen können, indem Sie den Punkt in-printf '.'
Jens
6
@Jens - besonders wenn Sie die Zeit berücksichtigen, die benötigt wird, um das zu tippen
Brian Agnew
6
Bei einem so kleinen Benchmark werden die Timings wahrscheinlich von anderen Faktoren als dem, was Sie messen möchten, dominiert. Ein Experiment mit einem großen Baum wäre nützlicher. Aber das bringt mich dazu, tatsächlich das zu tun, was das OP verlangt hat.
Tripleee
132

Warum nicht

find <expr> | wc -l

als einfache tragbare Lösung? Ihre ursprüngliche Lösung besteht darin , printf für jede einzelne gefundene Datei einen neuen Prozess zu erstellen, und das ist sehr teuer (wie Sie gerade gefunden haben).

Beachten Sie, dass dies zu viel zählt, wenn Sie Dateinamen mit eingebetteten Zeilenumbrüchen haben, aber wenn Sie diese haben, dann vermute ich, dass Ihre Probleme etwas tiefer gehen.

Brian Agnew
quelle
9
-1: bricht in der Datei mit Zeilenumbrüchen ab und ist langsamer als das Zählen von Bytes =)
Gilles Quenot
21
Ich glaube nicht, dass dies eine Ablehnung rechtfertigt, da die Beschränkung auf Dateinamen / Zeilenumbrüche ziemlich selten ist und oben erwähnt wurde. Langsamer ? Vielleicht. Angesichts der Tatsache, dass Sie ein Dateisystem abfragen, vermute ich, dass der Geschwindigkeitsunterschied gering ist. Über meine 10.000 Dateien messe ich 3ms Unterschied
Brian Agnew
8
Der Leistungsunterschied zwischen 'find <expr> | wc -l' und 'find <expr> -printf. | wc -c 'sind extrem klein. Das Zwischenspeichern (dh wenn Sie denselben Fund zweimal über denselben Baum ausführen) ist viel wichtiger. IMHO ist die Lösung mit "wc -l" viel intuitiver.
Pitseeker
4

Diese Lösung ist sicherlich langsamer als einige der anderen find -> wcLösungen hier, aber wenn Sie dazu neigten, zusätzlich zu deren Zählung noch etwas anderes mit den Dateinamen zu tun, könnten Sie dies readaus der findAusgabe heraus tun .

n=0
while read -r -d ''; do
    ((n++)) # count
    # maybe perform another act on file
done < <(find <expr> -print0)
echo $n

Es ist nur eine Modifikation einer in BashGuide gefundenen Lösung, die Dateien mit nicht standardmäßigen Namen ordnungsgemäß verarbeitet, indem das findAusgabetrennzeichen zu einem NUL-Byte gemacht print0und daraus ''(NUL-Byte) als Schleifenbegrenzer gelesen wird.

John B.
quelle
3

Dies ist meine countfilesFunktion in meiner ~/.bashrc(es ist ziemlich schnell, sollte für Linux & FreeBSD findfunktionieren und lässt sich nicht von Dateipfaden mit Newline-Zeichen täuschen; das Finale wczählt nur NUL-Bytes):

countfiles () 
{ 
   command find "${1:-.}" -type f -name "${2:-*}" -print0 | 
       command tr -dc '\0' | command wc -c;
return 0
}

countfiles

countfiles ~ '*.txt'
carlo
quelle