Réponse courte:
\ls -afq | wc -l
(Ceci inclut .
et ..
, donc soustrayez 2.)
Lorsque vous répertoriez les fichiers dans un répertoire, trois problèmes courants peuvent survenir:
- Enumérer les noms de fichiers dans le répertoire. C'est inévitable: il n'y a aucun moyen de compter les fichiers d'un répertoire sans les énumérer.
- Tri des noms de fichiers. Les caractères génériques de shell et la
ls
commande le font.
- Appel
stat
pour récupérer des métadonnées sur chaque entrée de répertoire, par exemple s'il s'agit d'un répertoire.
N ° 3 est de loin le plus cher, car il nécessite le chargement d’un inode pour chaque fichier. En comparaison, tous les noms de fichiers nécessaires pour # 1 sont stockés de manière compacte dans quelques blocs. # 2 gaspille un peu de temps CPU mais ce n'est souvent pas un facteur décisif.
S'il n'y a pas de nouvelles lignes dans les noms de fichiers, un simple ls -A | wc -l
indique le nombre de fichiers contenus dans le répertoire. Attention, si vous avez un alias pour ls
, cela peut déclencher un appel à stat
(par exemple, ls --color
ou si vous avez ls -F
besoin de connaître le type de fichier, ce qui nécessite un appel à stat
), c'est-à-dire à partir de la ligne de commande, appelez command ls -A | wc -l
ou \ls -A | wc -l
évitez un alias.
S'il y a des sauts de lignes dans le nom du fichier, le fait de savoir si les sauts de lignes sont répertoriés dépend de la variante Unix. GNU coreutils et BusyBox s’affichent ?
par défaut pour une nouvelle ligne, donc ils sont sûrs.
Appelez ls -f
pour lister les entrées sans les trier (# 2). Cela s'allume automatiquement -a
(au moins sur les systèmes modernes). L' -f
option est dans POSIX mais avec un statut optionnel; la plupart des implémentations le supportent, mais pas BusyBox. L'option -q
remplace les caractères non imprimables, y compris les retours à la ligne, par ?
; il s'agit de POSIX mais n'est pas pris en charge par BusyBox, alors omettez-le si vous avez besoin de la prise en charge de BusyBox au détriment du nombre excessif de fichiers dont le nom contient un caractère de nouvelle ligne.
Si le répertoire ne comporte pas de sous-répertoires, la plupart des versions de find
ne feront pas appel stat
à ses entrées (optimisation du répertoire feuille: un répertoire avec un nombre de liens égal à 2 ne peut pas avoir de sous-répertoires, il find
n'est donc pas nécessaire de rechercher les métadonnées des entrées sauf condition telle que l' -type
exige). Il find . | wc -l
existe donc un moyen rapide et portable de compter les fichiers dans un répertoire, à condition que celui-ci ne comporte aucun sous-répertoire et qu'aucun nom de fichier ne contienne de nouvelle ligne.
Si le répertoire ne contient pas de sous-répertoires mais que les noms de fichiers peuvent contenir des nouvelles lignes, essayez l'une d'entre elles (la deuxième devrait être plus rapide si elle est prise en charge, mais peut ne pas l'être de manière notable).
find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c
D'autre part, n'utilisez pas find
si le répertoire a des sous-répertoires: même des find . -maxdepth 1
appels stat
à chaque entrée (au moins avec GNU find et BusyBox find). Vous évitez de trier (# 2) mais vous payez le prix d'une recherche d'inode (# 3) qui tue les performances.
Dans le shell sans outils externes, vous pouvez exécuter compter les fichiers du répertoire en cours avec set -- *; echo $#
. Cela manque des fichiers point (fichiers dont le nom commence par .
) et signale 1 au lieu de 0 dans un répertoire vide. C’est le moyen le plus rapide de compter les fichiers dans les petits répertoires car il n’a pas besoin de démarrer un programme externe, mais (sauf dans zsh) une perte de temps pour les plus grands répertoires en raison de l’étape de tri (# 2).
En bash, c’est un moyen fiable de compter les fichiers du répertoire en cours:
shopt -s dotglob nullglob
a=(*)
echo ${#a[@]}
Dans ksh93, il s'agit d'un moyen fiable de compter les fichiers du répertoire en cours:
FIGNORE='@(.|..)'
a=(~(N)*)
echo ${#a[@]}
En zsh, c'est un moyen fiable de compter les fichiers du répertoire en cours:
a=(*(DNoN))
echo $#a
Si vous avez l' mark_dirs
ensemble des options, assurez - vous de le désactiver: a=(*(DNoN^M))
.
Dans n’importe quel shell POSIX, c’est un moyen fiable de compter les fichiers du répertoire en cours:
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"
Toutes ces méthodes trient les noms de fichiers, à l’exception de celui de zsh.
ls -l|wc -l
serait un par un en raison du nombre total de blocs dans la première ligne dels -l
sortie