Risposta breve:
\ls -afq | wc -l
(Ciò include .
e ..
, quindi, sottrarre 2.)
Quando si elencano i file in una directory, potrebbero accadere tre cose comuni:
- Enumerazione dei nomi dei file nella directory. Questo è inevitabile: non c'è modo di contare i file in una directory senza elencarli.
- Ordinamento dei nomi dei file. I caratteri jolly Shell e il
ls
comando lo fanno.
- Chiamata
stat
per recuperare metadati su ciascuna voce della directory, ad esempio se si tratta di una directory.
# 3 è di gran lunga il più costoso, perché richiede il caricamento di un inode per ciascun file. In confronto, tutti i nomi di file necessari per il numero 1 sono memorizzati in modo compatto in pochi blocchi. # 2 spreca un po 'di tempo della CPU ma spesso non è un problema.
Se non ci sono newline nei nomi dei file, un semplice ls -A | wc -l
ti dice quanti file ci sono nella directory. Attenzione che se si dispone di un alias per ls
, ciò può attivare una chiamata a stat
(ad esempio ls --color
o è ls -F
necessario conoscere il tipo di file, che richiede una chiamata a stat
), quindi dalla riga di comando, chiamare command ls -A | wc -l
o \ls -A | wc -l
per evitare un alias.
Se ci sono newline nel nome del file, se le newline sono elencate o meno dipende dalla variante Unix. I coreutils GNU e BusyBox vengono visualizzati ?
per impostazione predefinita per una nuova riga, quindi sono sicuri.
Chiama ls -f
per elencare le voci senza ordinarle (# 2). Questo si accende automaticamente -a
(almeno sui sistemi moderni). L' -f
opzione è in POSIX ma con stato opzionale; la maggior parte delle implementazioni lo supportano, ma non BusyBox. L'opzione -q
sostituisce i caratteri non stampabili incluse le nuove righe con ?
; è POSIX ma non è supportato da BusyBox, quindi omettilo se hai bisogno del supporto BusyBox a spese di un numero eccessivo di file il cui nome contiene un carattere di nuova riga.
Se la directory non ha sottodirectory, la maggior parte delle versioni find
non chiamerà le stat
sue voci (ottimizzazione delle directory foglia: una directory che ha un numero di collegamenti pari a 2 non può avere sottodirectory, quindi find
non è necessario cercare i metadati delle voci a meno che un condizione come lo -type
richiede). Quindi find . | wc -l
è un modo portatile e veloce per contare i file in una directory a condizione che la directory non abbia sottodirectory e che nessun nome di file contenga una nuova riga.
Se la directory non ha sottodirectory ma i nomi dei file possono contenere newline, prova una di queste (la seconda dovrebbe essere più veloce se supportata, ma potrebbe non esserlo in modo evidente).
find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c
D'altra parte, non usare find
se la directory ha delle sottodirectory: persino find . -maxdepth 1
chiamate stat
su ogni voce (almeno con GNU find e BusyBox find). Eviti l'ordinamento (n. 2) ma paghi il prezzo di una ricerca inode (n. 3) che uccide le prestazioni.
Nella shell senza strumenti esterni, è possibile eseguire contare i file nella directory corrente con set -- *; echo $#
. Questo manca i file punto (file il cui nome inizia con .
) e riporta 1 anziché 0 in una directory vuota. Questo è il modo più veloce per contare i file in piccole directory perché non richiede l'avvio di un programma esterno, ma (tranne in zsh) fa perdere tempo per directory più grandi a causa della fase di ordinamento (# 2).
In bash, questo è un modo affidabile per contare i file nella directory corrente:
shopt -s dotglob nullglob
a=(*)
echo ${#a[@]}
In ksh93, questo è un modo affidabile per contare i file nella directory corrente:
FIGNORE='@(.|..)'
a=(~(N)*)
echo ${#a[@]}
In zsh, questo è un modo affidabile per contare i file nella directory corrente:
a=(*(DNoN))
echo $#a
Se avete il mark_dirs
set di opzione, assicurarsi di spegnerlo: a=(*(DNoN^M))
.
In qualsiasi shell POSIX, questo è un modo affidabile per contare i file nella directory corrente:
total=0
set -- *
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- .[!.]*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- ..?*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
echo "$total"
Tutti questi metodi ordinano i nomi dei file, tranne quello zsh.
ls -l|wc -l
sarebbe spento di uno a causa dei blocchi totali nella prima riga dils -l
output