C'è qualcosa di più veloce di `find. | wc -l` per contare i file in una directory?


8

Non di rado devo contare il numero di file in una directory, a volte questo va a milioni.

Esiste un modo migliore di elencarli e contarli find . | wc -l? Esiste un tipo di chiamata al filesystem che puoi effettuare su ext3 / 4 che richiede meno I / O?


3
Non stai contando solo i file, ma anche le directory. Se vuoi solo contare i file, usa "trova. -Tipo f | wc -l" se vuoi contare collegamenti simbolici e file regolari, usa "trova. -Tipo f -o -tipo l | wc -l"
FSMaxB

Una directory è una specie di file, così come dispositivi, collegamenti simbolici e socket. I file regolari sono un sottoinsieme di file.
Toby Speight,

1
L'esempio che fai suggerisce che vuoi un conteggio ricorsivo - se no, allora hai bisogno find -maxdepth 1. Nota che con il tuo approccio attuale, conterai due volte qualsiasi nome che contiene un carattere di nuova riga.
Toby Speight,

Risposte:


13

Non un accelerazione fondamentale ma almeno qualcosa :)

find . -printf \\n | wc -l

Non hai davvero bisogno di passare l'elenco dei nomi dei file, solo le newline sono sufficienti. Questa variante è circa il 15% più veloce sul mio Ubuntu 12.04.3 quando le directory sono memorizzate nella cache nella RAM. Inoltre questa variante funzionerà correttamente con nomi di file contenenti newline.

È interessante notare che questa variante sembra essere un po 'più lenta di quella sopra:

find . -printf x | wc -c

Caso speciale - ma davvero veloce

Se la directory si trova sul suo file system, puoi semplicemente contare gli inode:

df -i .

Se il numero di directory e file in directory diverse da quella contata non cambia molto, puoi semplicemente sottrarre questo numero noto dal df -irisultato corrente . In questo modo sarai in grado di contare i file e le directory molto rapidamente.


"Questa variante è circa il 15% più veloce ..." mi chiedo se ci sia qualche tipo di trucco utile che stai usando per cronometrare?
Brian Z,

4
@BrianZ: puoi cronometrare un comando anteponendo il comando con il tempo. time find /usr/src/ -printf \\n | wc -l, puoi cancellare le cache tra una corsa e l' sudo sync && sudo sysctl -w vm.drop_caches=3
altra

Quindi ho visto un consistente aumento del 2% della velocità con una delle prime 2 opzioni senza memorizzazione nella cache. Quindi sì, è un modo piuttosto interessante di farlo. Il conteggio degli inode è sicuramente il migliore se l'ambiente è configurato per questo. Non l'avevo considerato.
MattPark,

È -printf xpensato per essere lo stesso di -printf '\0'? Non lo vedo menzionato nei documenti.
CMCDragonkai,

@CMCDragonkai: l'azione -printffunziona in modo simile alla printf()funzione in C con la differenza principale che le %direttive hanno un significato diverso. L'azione viene invocata per ogni file trovato. Ciò significa che -printf xstamperà il carattere xper ogni file trovato (provalo!) E -printf '\0'stamperà il carattere NULL (codice ASCII 0) per ogni file trovato. -printf '\0'non ha un significato speciale. Entrambi funzioneranno allo stesso modo nell'esempio con wc -cin questa risposta.
pabouk,

3

Ho scritto ffcnt esattamente per quello scopo. Recupera l'offset fisico delle directory stesse con lo fiemapioctl e quindi pianifica l'attraversamento della directory in più passaggi sequenziali per ridurre l'accesso casuale. Se si ottiene effettivamente uno speedup rispetto a find | wc dipende da diversi fattori:

  • tipo di filesystem: filesystem come ext4 che supportano lo fiemapioctl ne trarranno maggiori benefici
  • velocità di accesso casuale: gli HDD ne beneficiano molto più degli SSD
  • layout di directory: maggiore è il numero di directory nidificate, maggiore è il potenziale di ottimizzazione

(ri) il montaggio con relatimeo addirittura nodiratimepotrebbe anche migliorare la velocità (per tutti i metodi) quando gli accessi causerebbero altrimenti aggiornamenti dei metadati.


L'ultima frase è un suggerimento utile! Penso che il link al tuo programma sarebbe migliorato se aggiungessi un riepilogo di come funziona. Preferiamo risposte complete in se stesse, nel caso in cui accada qualcosa di brutto alla risorsa collegata (ma ovviamente manteniamo anche il collegamento).
Toby Speight,

2

In realtà, sul mio sistema (Arch Linux) questo comando

   ls -A | wc -l

è più veloce di tutto quanto sopra:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

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

Penso che il problema con ls sia che spesso restituisce qualcosa come /bin/ls: Argument list too longse usi il globbing, ma poi può funzionare in modo ricorsivo come trova anche, quindi forse è qualcosa da considerare, non usare find se non necessario.
MattPark,

Sembra così tardi (molti anni) commentarlo, ma ls -Aelenca solo i file nella directory corrente mentre findsenza -maxdepth 1argomenti effettuerà una ricerca ricorsiva in tutte le sottodirectory.
Luciano,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.