Qual è il modo migliore per contare il numero di file in una directory?


11

Se analizzare l'output di lsè pericoloso perché può rompersi su alcuni caratteri funky (spazi,, \n...), qual è il modo migliore per conoscere il numero di file in una directory?

Di solito mi affido findper evitare questo parsing, ma allo stesso modo, find mydir | wc -lsi romperà per gli stessi motivi.

Sto lavorando su Solaris in questo momento, ma sto cercando una risposta il più portatile possibile tra diversi sistemi e shell.


3
Non sono sicuro che sia un duplicato, mi sto perdendo qualcosa?
Rahmu,

1
Questo potrebbe essere un duplicato, ma non della domanda indicata. findriceverà il numero di file in modo ricorsivo (utilizzare -maxdepth 1se non lo si desidera. find mydir -maxdepth 1 -type f -printf \\n | wc -ldovrebbe gestire i caratteri speciali nel nome del file, in quanto non vengono mai stampati in primo luogo.
Anthon,

Risposte:


16

Che ne dici di questo trucco?

find . -maxdepth 1 -exec echo \; | wc -l

Portatile come finde wc.


5
Questo non funziona (visualizza i n+1file sul mio sistema Debian). Inoltre, non filtra i file normali.
Chris Down,

4
Ho appena fatto un esempio generico. Funziona, ma come funziona dipende da come si adatta il findcomando alle proprie esigenze specifiche. Sì, questo include tutte le directory, incluso .(che potrebbe essere il motivo per cui vedi il risultato come n+1).
rozcietrzewiacz,

Mi piace questo trucco, molto intelligente; ma sono sorpreso che non ci sia un modo semplice e semplice per farlo!
Rahmu,

3
@ChrisDown l'OP non specifica il filtro per i file normali, chiede il numero di file in una directory. Per eliminare il problema n + 1, utilizzare find . -maxdepth 1 ! -name . -exec echo \; | wc -l; alcune versioni precedenti di findnon hanno -not.
Arcege,

3
Nota che -maxdepthnon è standard (un'estensione GNU ora è supportata anche da alcune altre implementazioni).
Stéphane Chazelas,

11

Con bash, senza utility esterne, né loop:

shopt -s dotglob
files=(*)
echo ${#files[@]}

In ksh, sostituisci shopt -s dotglobcon FIGNORE=.?(.). In zsh, sostituirlo con setopt glob_dotso rimuovere la shoptchiamata e utilizzare files=(*(D)). (O semplicemente rilasciare la linea se non si desidera includere file dot.) Portabilmente, se non ti interessa i file dot:

set -- *
echo $#

Se si desidera includere file dot:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c

2
Il primo esempio viene stampato 1per una directory vuota quando nullglobnon è abilitato. In zsh, a=(*(DN));echo ${#a}con il qualificatore N( nullglob) non risulta un errore per una directory vuota.
nisetama,

8
find . ! -name . -prune -print | grep -c /

Dovrebbe essere abbastanza portatile per i sistemi post-80.

Ciò conta tutte le voci della directory tranne .e ..nella directory corrente.

Per contare i file anche nelle sottodirectory:

find .//. ! -name . | grep -c //

(quello dovrebbe essere portatile anche su Unix V6 (1975), dal momento che non è necessario -prune)


Una delle rare risposte portatili su questa pagina, se non l'unica.
Xhienne,

Ho votato questa risposta ieri perché ho scoperto che funziona anche con directory diverse dalla directory corrente ( find dirname ! -name dirname -prune -print). Da allora mi chiedevo se ci fosse qualche motivo particolare da usare al grep -c /posto di wc -l(che è probabilmente più comunemente usato per il conteggio).
Anthony Geoghegan,

1
find dirname ! -name dirnamenon funziona se ci sono altre directory all'interno che hanno un nome dirname. È meglio usare find dirname/. ! -name .. wc -lconta il numero di righe, i nomi dei file possono essere costituiti da più righe poiché il carattere di nuova riga è valido come qualsiasi altro in un nome di file.
Stéphane Chazelas,

6

Provare:

ls -b1A | wc -l

Il -bavranno caratteri non stampabili, -Amostrerà tutti i file ad eccezione .ed ..e uno per riga (di default su un tubo, ma buona per essere espliciti).

Finché includiamo linguaggi di scripting di livello superiore, ecco un one-liner in Python:

python -c 'import os; print len(os.listdir(os.sep))'

O con 'trova' completo:

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'

1

Yoc può usare tale costruzione:

I=0; for i in * ; do ((I++)); done ; echo $I

Ma ho paura, puoi catturare l'errore come Argument list too long.se avessi troppi file nella directory. Tuttavia l'ho provato su una directory con 10 miliardi di file e ha funzionato bene.


3
Questo non funzionerà neanche per i file nascosti a meno che la shell non sia configurata per espandere quelli con *.
Lekensteyn,

gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley,

4
@ Rush: questo comando non dovrebbe mai aumentare "arg list troppo a lungo". Ciò accade solo con un comando esterno (quindi mai con for.
enzotib il

1

Hai considerato perl, che dovrebbe essere relativamente portatile?

Qualcosa di simile a:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";

0

Prova questo => Usando ls con -i (per il numero del nodo) e -F (accoda il nome della directory con '/').

ls -ilF | egrep -v '/' | wc -l

0

Con un perlliner (riformattato per leggibilità):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

o

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

È possibile utilizzare perlfunzioni che modificano array come grepo mapcon la seconda versione. Vedi perldoc -f readdirper un esempio usando grep.


0

La versione più semplice che uso sempre e con cui non ho mai avuto problemi è: ls -b1 | wc -l


Potresti incorrere in problemi se il nome del file contiene uno \no altri caratteri funky (sì, alcuni unice lo consentono).
rahmu,

1
L'ho provato esplicitamente prima di pubblicare la mia risposta e non ho avuto problemi. Ho usato il file manager nautilus per rinominare un file per contenere \ n per provare questo.
Peter,

Hai ragione, non funziona così. Non so cosa ho fatto quando ho provato prima questo. Ho provato di nuovo e aggiornato la mia risposta.
Peter,

No, il comando è OK, ma esiste già una soluzione simile e i file nascosti non vengono conteggiati.
Xhienne,

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.