Conteggio ricorsivo dei file in una directory Linux


728

Come posso contare ricorsivamente i file in una directory Linux?

Ho trovato questo:

find DIR_NAME -type f ¦ wc -l

Ma quando eseguo questo restituisce il seguente errore.

trova: i percorsi devono precedere l'espressione: ¦


64
Stai confondendo la barra spezzata ¦(ASCII 166) con la barra verticale |(ASCII 124) utilizzata per la pipeline UNIX .
Skippy le Grand Gourou,

7
@SkippyleGrandGourou Non si chiama pipe?
DaveStephens,

27
@DaveStephens Sì, si chiama anche così. Si chiama anche colpo di Sheffer, verti-bar, vbar, stick, linea verticale, barra verticale, barra, obelisco, glidus.
emlai,

64
@zenith l'ho appena chiamato Bob.
Christopher,

15
In RFC20 si chiama "linea verticale". "Pipe" è il nome dell'operatore shell, piuttosto che il nome del simbolo. Proprio come *il carattere ASCII "asterisco", ma "volte" in alcuni altri contesti.
magro,

Risposte:


1327

Questo dovrebbe funzionare:

find DIR_NAME -type f | wc -l

Spiegazione:

  • -type f per includere solo i file.
  • |( e non¦ ) reindirizza findl'output standard del wccomando all'input standard del comando.
  • wc(abbreviazione di conteggio parole) conta nuove righe, parole e byte sul suo input ( documenti ).
  • -l contare solo le nuove righe.

Appunti:

  • Sostituisci DIR_NAMEcon .per eseguire il comando nella cartella corrente.
  • Puoi anche rimuovere le -type fdirectory da includere (e i collegamenti simbolici) nel conteggio.
  • È possibile che questo comando superi il numero se i nomi dei file possono contenere caratteri di nuova riga.

Spiegazione del motivo per cui il tuo esempio non funziona:

Nel comando che hai mostrato, non usi "Pipe" ( |) per collegare due comandi, ma la barra spezzata ( ¦) che la shell non riconosce come comando o qualcosa di simile. Ecco perché ricevi quel messaggio di errore.


27
Il fin -type facronimo di file e wc -lper le linee di conteggio di parola.
Serge Stroobandt,

3
Rimuovere le -type fdirectory da includere nel conteggio
phatblat,

3
Non è necessario per la -printbandiera
Zoltán,

3
Se è possibile che i nomi dei file contengano il carattere di nuova riga, è possibile che si desideri utilizzare il -print0flag.
gaboroncancio,

2
@gaboroncancio Non sarà d'aiuto, a meno che alcune implementazioni di wcabbiano un'opzione per leggere un elenco con terminazione null. Vedi la mia risposta per un'alternativa.
Ripristina Monica Please il

100

Per la directory corrente:

find -type f | wc -l

5
Questa soluzione non tiene conto del nome file che contiene nuove righe.
Kusalananda,

2
Per la directory corrente, non hai nemmeno bisogno di.
baptx il

1
In realtà, su alcune piattaforme, si fa necessario precisarefind .
tripleee

1
@Kusalanandra Il tuo commento si applica a quasi tutte le risposte qui.
Tripleee

69

Se vuoi una ripartizione di quanti file sono presenti in ogni directory sotto la tua directory corrente:

for i in */ .*/ ; do 
    echo -n $i": " ; 
    (find "$i" -type f | wc -l) ; 
done

Questo può andare tutto su una riga, ovviamente. La parentesi chiarisce di chi wc -ldovrebbe essere l' output a guardare ( find $i -type fin questo caso).


7
Potrebbe rimanere bloccato nelle directory con spazi nei loro nomi. Cambiando la prima riga per find . -maxdepth 1 -type d -print0 | while IFS= read -r -d '' i ; dorisolverlo. Vedi Come posso leggere un file (flusso di dati, variabile) riga per riga (e / o campo per campo)?
Arch Stanton,

4
L'uso findper l'anello esterno è solo una complicazione inutile. for i in */; do`
tripleee,

funzione countit {per i in $ (find. -maxdepth 1 -type d); do file_count = $ (trova $ i -type f | wc -l); echo "$ file_count: $ i"; fatto }; countit | sort -n -r
Schneems,

Finalmente questo è quello di cui avevo bisogno. Le mie cartelle hanno migliaia di file, quindi stamparli con l'albero o qualsiasi altra cosa non è un'opzione
lesolorzanov,

Questo include ../ e non sembra andare avanti, il che significa che non è regressivo.
Daniel Lefebvre,

50

Puoi usare

$ tree

dopo aver installato il pacchetto albero con

$ sudo apt-get install tree

(su una macchina Debian / Mint / Ubuntu Linux).

Il comando mostra non solo il conteggio dei file, ma anche il conteggio delle directory, separatamente. L'opzione -L può essere utilizzata per specificare il livello di visualizzazione massimo (che, per impostazione predefinita, è la profondità massima della struttura di directory).

Anche i file nascosti possono essere inclusi fornendo l' -aopzione.


4
Questo è in realtà il modo più semplice per vedere il numero di directory e file.
Lorem Ipsum Dolor,

11
Dalla pagina man: per impostazione predefinita l'albero non stampa i file nascosti . Devi fornire l' -aopzione per includerli.
Eee,

3
Per installarlo su macOS, usa brewed esegui brew install tree, preferibilmente dopo l'esecuzione brew update.
Ashish Ahuja,

4
Stampa anche tutti i nomi dei file, quindi sarà lento se hai molti file.
Franck Dernoncourt,

2
Caspita, ottimo strumento, può stampare cartelle colorate, elencare solo cartelle, output come JSON. Può elencare 34k cartelle e 51k file in pochissimi secondi. Olé!
brasofilo,

46

Sul mio computer, rsyncè un po 'più veloce rispetto find | wc -lalla risposta accettata:

$ rsync --stats --dry-run -ax /path/to/dir /tmp

Number of files: 173076
Number of files transferred: 150481
Total file size: 8414946241 bytes
Total transferred file size: 8414932602 bytes

La seconda riga ha il numero di file, 150.481 nell'esempio sopra. Come bonus ottieni anche la dimensione totale (in byte).

Osservazioni:

  • la prima riga è un conteggio di file, directory, collegamenti simbolici, ecc. tutti insieme, ecco perché è più grande della seconda riga.
  • l' opzione --dry-run(o -nin breve) è importante per non trasferire effettivamente i file!
  • Ho usato l' -xopzione per "non oltrepassare i confini del filesystem", il che significa che se lo esegui /e hai dei dischi rigidi esterni collegati, conterà solo i file sulla partizione di root.

Mi piace la tua idea di usare rsync qui. Non ci avrei mai pensato!
Qeole,

Grazie @Qeole, l'idea non è mia però. L'ho letto diversi anni fa da qualche parte che rsync è il più veloce per eliminare una cartella con molti file e sottocartelle, quindi ho pensato che potesse essere veloce contare anche i file.
psmith,

1
Ho provato questo. Dopo aver eseguito entrambi due volte in anticipo per popolare la cache di fs, ci sono find ~ -type f | wc -lvoluti 1,7 / 0,5 / 1,33 secondi (reale / utente / sys). rsync --stats --dry-run -ax ~ /xxximpiegato 4.4 / 3.1 / 2.1 secondi. Questo per circa 500.000 file su SSD.
magro,

Non so quale versione di rsync hai usato, ma in 3.1.2 è un po 'più facile da leggere:Number of files: 487 (reg: 295, dir: 192)
mpen

Ho usato il rsync predefinito su macOS:rsync version 2.6.9 protocol version 29
psmith

20

Poiché i nomi di file in UNIX possono contenere newline (sì, newline), è wc -lpossibile che vengano conteggiati troppi file. Vorrei stampare un punto per ogni file e quindi contare i punti:

find DIR_NAME -type f -printf "." | wc -c

1
Sembra che questa sia l'unica soluzione che gestisce i file con newline nei loro nomi. Upvoted.
codeforester

2
hihi :) Adoro le newline nei nomi dei file. Questo li rende solo più leggibili.
hek2mgl,

Voglio dire, i newline nei nomi dei file non nel contenuto!
codeforester

1
Stavo solo scherzando ... Sì, le nuove righe nei nomi dei file devono sempre essere prese in considerazione. Potrebbero provenire da contenuti dannosi o meno spettacolari, da un errore di battitura.
hek2mgl,

18

Combinando insieme alcune delle risposte qui, la soluzione più utile sembra essere:

find . -maxdepth 1 -type d -print0 |
xargs -0 -I {} sh -c 'echo -e $(find "{}" -printf "\n" | wc -l) "{}"' |
sort -n

Può gestire cose strane come nomi di file che includono spazi tra parentesi e persino nuove righe. Ordina inoltre l'output in base al numero di file.

È possibile aumentare il numero dopo -maxdepthper contare anche le sottodirectory. Tieni presente che ciò potrebbe richiedere molto tempo, in particolare se hai una struttura di directory altamente nidificata in combinazione con un -maxdepthnumero elevato .


Cosa c'è con il echo -e? Immagino che tu l'abbia inserito per piegare qualsiasi nuova riga, ma rovinerà anche qualsiasi altro spazio bianco irregolare e tenterà di espandere qualsiasi carattere jolly presente alla lettera nei nomi dei file. Andrei semplicemente con qualcosa di simile find .* * -type d -execdir sh -c 'find . -type f -printf "\n" | wc -l; pwd'e vivrei con qualsiasi aberrazione nell'output, o forse avrei giocato con Bash printf "%q"per stampare il nome della directory.
Tripleee,

10

Se vuoi sapere quanti file e sottodirectory esistono dalla presente directory di lavoro, puoi usare questo one-liner

find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo -e $(find {} | wc -l) {}' | sort -n

Funzionerà con GNU, e omette -e dal comando echo per BSD linux (es. OSX).


2
Ottima soluzione! L'unico problema che ho riscontrato erano le directory con spazi o caratteri speciali. Aggiungi le virgolette in cui viene utilizzato il nome della find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo -e $(find "{}" | wc -l) "{}"' | sort -n
directory

1
L'ho modificato un po 'e funziona abbastanza bene per me:find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo $(find {} | wc -l) \\t {}' | sort -rn | less
Wizek

I miei commenti sulla risposta di @ Sebastian si applicano anche qui. L'uso di echo -e(o semplicemente `echo` come nel commento precedente) su un nome di directory non quotato scambia un problema con un altro.
Tripleee

8

Se si desidera evitare casi di errore, non consentire la wc -lvisualizzazione di file con newline (che verranno conteggiati come 2+ file)

ad esempio, considera un caso in cui abbiamo un singolo file con un singolo carattere EOL in esso

> mkdir emptydir && cd emptydir
> touch $'file with EOL(\n) character in it'
> find -type f
./file with EOL(?) character in it
> find -type f | wc -l
2

Poiché almeno gnu wcnon sembra avere un'opzione per leggere / contare un elenco con terminazione null (tranne che da un file), la soluzione più semplice sarebbe semplicemente non passargli i nomi dei file, ma un output statico ogni volta che viene trovato un file, ad es. nella stessa directory di cui sopra

> find -type f -exec printf '\n' \; | wc -l
1

O se findlo supporta

> find -type f -printf '\n' | wc -l
1 

7

È possibile utilizzare il comando ncdu. Conterà ricorsivamente quanti file contiene una directory Linux. Ecco un esempio di output:

inserisci qui la descrizione dell'immagine

Ha una barra di avanzamento, che è utile se hai molti file:

inserisci qui la descrizione dell'immagine

Per installarlo su Ubuntu:

sudo apt-get install -y ncdu

Punto di riferimento: ho usato https://archive.org/details/cv_corpus_v1.tar (380390 file, 11 GB) come cartella in cui si deve contare il numero di file.

  • find . -type f | wc -l: circa 1m20s per il completamento
  • ncdu: circa 1m20s per il completamento

Ciò calcola principalmente l'utilizzo del disco, non il numero di file. Questo sovraccarico aggiuntivo non è probabilmente voluto. (oltre alla necessità di installare un pacchetto aggiuntivo per qualcosa che può essere fatto con utility POSIX standard)
hek2mgl

@ hek2mgl Calcola il numero di file, come mostrato in rosso nel primo screenshot. Mi ci sono voluti alcuni minuti per ~ 2 milioni di file, quindi la velocità non è male.
Franck Dernoncourt,

2
@ hek2mgl Ho aggiunto un benchmark riproducibile nella risposta, l'ho eseguito due volte e non ho notato alcuna differenza tra find . -type f | wc -le ncdu.
Franck Dernoncourt,

2
sì, sembra che si findstia eseguendo più o meno le stesse chiamate di sistema di ducui è il backend ncdu. Li ho appena rintracciati.
hek2mgl,

1
@FranckDernoncourt è piaciuto molto. Ho un sacco di file in una cartella e avere una barra di avanzamento è salva-vita. Grazie per la condivisione!
Geek,


4

Per determinare quanti file ci sono nella directory corrente, inserire ls -1 | wc -l. Questo utilizza wcper fare un conteggio del numero di righe (-l)nell'output di ls -1. Non conta i dotfile. Si noti che ls -l(questa è una "L" piuttosto che un "1" come negli esempi precedenti) che ho usato nelle versioni precedenti di questo HOWTO in realtà vi darà un conteggio di file superiore a quello effettivo. Grazie a Kam Nejad per questo punto.

Se vuoi contare solo i file e NON includere collegamenti simbolici (solo un esempio di cos'altro potresti fare), potresti usare ls -l | grep -v ^l | wc -l(questa volta questa è una "L" e non un "1", qui vogliamo un elenco "lungo") . grepcontrolla qualsiasi riga che inizia con "l" (che indica un collegamento) e scarta quella linea (-v).

Velocità relativa: "ls -1 / usr / bin / | wc -l" richiede circa 1,03 secondi su un 486SX25 non caricato (/ usr / bin / su questa macchina ha 355 file). " ls -l /usr/bin/ | grep -v ^l | wc -l" richiede circa 1,19 secondi.

Fonte: http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x700.html


2
ls -ldeve fare statsyscall su ogni file per leggere le sue dimensioni, mtime e altre proprietà, che è lenta. Nelle grandi directory (oltre 100.000 file) l'esecuzione ls -lpuò richiedere alcuni minuti. Quindi, per contare solo i file, usa sempre ls -1 | wc -l.
Marki555,

A 486SX25, bello
cam8001,

ls -1può ancora essere lento in directory di grandi dimensioni, perché deve ordinare i file. Fa semplicemente printf '%s\n' *la stessa cosa ed evita la lschiamata esterna (che è comunque problematica ) ma il soluton più efficiente è usare un comando che non esegue alcun ordinamento, come find. (L'output glob è ordinato per shell.)
Tripleee

4

Se ciò di cui hai bisogno è contare ricorsivamente un tipo di file specifico , puoi fare:

find YOUR_PATH -name '*.html' -type f | wc -l 

-l è solo per visualizzare il numero di righe nell'output.


L'estensione fa parte del nome file e potrebbe non rappresentare il file TYPE
Waxhead

4

Con bash:

Crea una matrice di voci con () e ottieni il con #.

FILES=(./*); echo ${#FILES[@]}

Ok, non conta in modo ricorsivo i file ma prima volevo mostrare la semplice opzione. Un caso d'uso comune potrebbe essere la creazione di backup di rollover di un file. Questo creerà logfile.1, logfile.2, logfile.3 ecc.

CNT=(./logfile*); mv logfile logfile.${#CNT[@]}

Conteggio ricorsivo con bash 4+ globstarabilitato (come indicato da @tripleee)

FILES=(**/*); echo ${#FILES[@]}

Per ottenere il conteggio dei file in modo ricorsivo possiamo ancora usare find allo stesso modo.

FILES=(`find . -type f`); echo ${#FILES[@]}

Supporto di shell moderne **/*per l'enumerazione ricorsiva. È ancora meno efficiente rispetto findalle directory di grandi dimensioni perché la shell deve ordinare i file in ciascuna directory.
tripleee

2

Per le directory con spazi nel nome ... (basato su varie risposte sopra) - stampa ricorsivamente il nome della directory con il numero di file all'interno di:

find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done

Esempio (formattato per la leggibilità):

pwd
  /mnt/Vancouver/Programming/scripts/claws/corpus

ls -l
  total 8
  drwxr-xr-x 2 victoria victoria 4096 Mar 28 15:02 'Catabolism - Autophagy; Phagosomes; Mitophagy'
  drwxr-xr-x 3 victoria victoria 4096 Mar 29 16:04 'Catabolism - Lysosomes'

ls 'Catabolism - Autophagy; Phagosomes; Mitophagy'/ | wc -l
  138

## 2 dir (one with 28 files; other with 1 file):
ls 'Catabolism - Lysosomes'/ | wc -l
  29

La struttura della directory viene visualizzata meglio usando tree:

tree -L 3 -F .
  .
  ├── Catabolism - Autophagy; Phagosomes; Mitophagy/
  │   ├── 1
  │   ├── 10
  │   ├── [ ... SNIP! (138 files, total) ... ]
  │   ├── 98
  │   └── 99
  └── Catabolism - Lysosomes/
      ├── 1
      ├── 10
      ├── [ ... SNIP! (28 files, total) ... ]
      ├── 8
      ├── 9
      └── aaa/
          └── bbb

  3 directories, 167 files

man find | grep mindep
  -mindepth levels
    Do not apply any tests or actions at levels less than levels
    (a non-negative integer).  -mindepth 1 means process all files
    except the starting-points.

ls -p | grep -v /(utilizzato di seguito) proviene dalla risposta 2 all'indirizzo /unix/48492/list-only-regular-files-but-not-directories-in-current-directory

find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done
./Catabolism - Autophagy; Phagosomes; Mitophagy: 138
./Catabolism - Lysosomes: 28
./Catabolism - Lysosomes/aaa: 1

Applcation: Voglio trovare il numero massimo di file tra diverse centinaia di directory (tutta la profondità = 1) [l'output di seguito è stato nuovamente formattato per la leggibilità]:

date; pwd
    Fri Mar 29 20:08:08 PDT 2019
    /home/victoria/Mail/2_RESEARCH - NEWS

time find . -mindepth 1 -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done > ../../aaa
    0:00.03

[victoria@victoria 2_RESEARCH - NEWS]$ head -n5 ../../aaa
    ./RNA - Exosomes: 26
    ./Cellular Signaling - Receptors: 213
    ./Catabolism - Autophagy; Phagosomes; Mitophagy: 138
    ./Stress - Physiological, Cellular - General: 261
    ./Ancient DNA; Ancient Protein: 34

[victoria@victoria 2_RESEARCH - NEWS]$ sed -r 's/(^.*): ([0-9]{1,8}$)/\2: \1/g' ../../aaa | sort -V | (head; echo ''; tail)

    0: ./Genomics - Gene Drive
    1: ./Causality; Causal Relationships
    1: ./Cloning
    1: ./GenMAPP 2
    1: ./Pathway Interaction Database
    1: ./Wasps
    2: ./Cellular Signaling - Ras-MAPK Pathway
    2: ./Cell Death - Ferroptosis
    2: ./Diet - Apples
    2: ./Environment - Waste Management

    988: ./Genomics - PPM (Personalized & Precision Medicine)
    1113: ./Microbes - Pathogens, Parasites
    1418: ./Health - Female
    1420: ./Immunity, Inflammation - General
    1522: ./Science, Research - Miscellaneous
    1797: ./Genomics
    1910: ./Neuroscience, Neurobiology
    2740: ./Genomics - Functional
    3943: ./Cancer
    4375: ./Health - Disease 

sort -Vè un tipo naturale. ... Quindi, il mio numero massimo di file in una di quelle directory (Claws Mail) è di 4375 file. Se avessi lasciato il pad ( https://stackoverflow.com/a/55409116/1904943 ) quei nomi di file - sono tutti nominati numericamente, a partire da 1, in ciascuna directory - e pad a 5 cifre totali, dovrei essere ok .


appendice

Trova il numero totale di file, sottodirectory in una directory.

$ date; pwd
Tue 14 May 2019 04:08:31 PM PDT
/home/victoria/Mail/2_RESEARCH - NEWS

$ ls | head; echo; ls | tail
Acoustics
Ageing
Ageing - Calorie (Dietary) Restriction
Ageing - Senescence
Agriculture, Aquaculture, Fisheries
Ancient DNA; Ancient Protein
Anthropology, Archaeology
Ants
Archaeology
ARO-Relevant Literature, News

Transcriptome - CAGE
Transcriptome - FISSEQ
Transcriptome - RNA-seq
Translational Science, Medicine
Transposons
USACEHR-Relevant Literature
Vaccines
Vision, Eyes, Sight
Wasps
Women in Science, Medicine

$ find . -type f | wc -l
70214    ## files

$ find . -type d | wc -l
417      ## subdirectories

1

Ho scritto ffcnt per accelerare il conteggio dei file ricorsivi in ​​circostanze specifiche: dischi rotazionali e filesystem che supportano la mappatura dell'estensione.

Può essere un ordine di grandezza più veloce lso findbasato su approcci, ma YMMV.


0

Ci sono molte risposte corrette qui. Eccone un altro!

find . -type f | sort | uniq -w 10 -c

dove si .trova la cartella in cui cercare ed 10è il numero di caratteri per cui raggruppare la directory.


-1

trova-tipo f | wc -l

OPPURE (Se la directory è la directory corrente)

trova . -tipo f | wc -l


Questo duplica almeno un'altra risposta a questa stessa domanda.
Kusalananda,

-1

Funzionerà perfettamente. Insomma semplice. Se si desidera contare il numero di file presenti in una cartella.

ls | wc -l

3
Innanzitutto, questo non risponde alla domanda. La domanda riguarda il conteggio ricorsivo dei file da una directory in avanti e il comando mostrato non lo fa. inoltre, con ls stai contando directory e file. Inoltre, non vi è alcun motivo di rispondere a una vecchia domanda se non si intende aggiungere nulla di nuovo e non si intende nemmeno leggere correttamente la domanda. Per favore, astieniti dal farlo.
XFCC

-1

Questo approccio alternativo con il filtro per il formato conta tutti i moduli del kernel grub disponibili:

ls -l /boot/grub/*.mod | wc -l

-3
ls -l | grep -e -x -e -dr | wc -l 
  1. lunga lista
  2. filtra file e directory
  3. contare la linea filtrata n
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.