Trouver le nombre de fichiers dans un répertoire
y a-t-il une méthode dans Linux pour calculer le nombre de fichiers dans un répertoire (c'est-à-dire les enfants immédiats) dans O(1) (indépendamment du nombre de fichiers) sans avoir à lister le répertoire en premier? Si non O (1), y a-t-il un moyen raisonnablement efficace?
je suis à la recherche d'une alternative à l' ls | wc -l
.
8 réponses
readdir n'est pas aussi cher que vous le pensez. Le truc est d'éviter de stater chaque fichier, et (optionnellement) de trier la sortie de ls.
/bin/ls -1U | wc -l
évite les alias dans votre shell, ne trie pas la sortie, et liste 1 Fichier-par-ligne (pas strictement nécessaire lorsque la sortie est raccordée au wc).
La question peut être reformulée comme "la structure de données d'un répertoire de stocker le nombre d'entrées?", pour laquelle la réponse est non. Il n'y a pas un moyen plus efficace de compter les fichiers que readdir(2)/getdents(2).
on peut obtenir le nombre de sous-répertoires d'un répertoire donné sans traverser toute la liste en stat'ing (stat(1) ou stat(2)) le répertoire donné et en observant le nombre de liens vers ce répertoire. Un répertoire donné avec N répertoires enfant aura un nombre de liens N+2, un lien pour le ".."l'entrée de chaque sous-répertoire, en plus de deux pour le "." et." ."les entrées du répertoire donné.
cependant, on ne peut pas obtenir le nombre de tous les fichiers (qu'il s'agisse de fichiers réguliers ou sous-répertoires) sans parcourir toute la liste -- c'est correct.
la commande"/bin / ls-1U " n'obtiendra pas toutes les entrées cependant. Il obtiendra les entrées de répertoire qui ne commencent pas par le point (.) caractère. Par exemple, il ne compterait pas le ".profil " fichier trouvé dans de nombreux répertoires login $HOME.
on peut utiliser la commande "/bin/ls-F" ou la commande "/bin/ls-Ua" pour éviter le tri et obtenir toutes les entrées.
peut-être malheureusement pour vos besoins, la commande "/bin/ls-F" ou la commande "/bin/ls-Ua" comptera aussi "." et." ."les entrées dans chaque répertoire. Vous devrez soustraire 2 du compte pour éviter de compter ces deux entrées, comme dans les suivantes:
expr `/bin/ls -f | wc -l` - 2 # Those are back ticks, not single quotes.
l'option -- format=single-column (-1) n'est pas nécessaire sur la commande "/bin/ls-Ua" lorsque vous pipez la sortie "ls", comme dans "wc" dans ce cas. La commande" ls " écrira automatiquement sa sortie dans un colonne unique si la sortie n'est pas un terminal.
-U
option pour ls
n'est pas dans POSIX, et dans OS X ls
il a une signification différente de GNU ls
, qui est qu'il fait -t
et -l
utilisez les temps de création au lieu des temps de modification. -f
est POSIX comme extension XSI. Le manuel de GNU ls
décrit -f
do not sort, enable -aU, disable -ls --color
et -U
do not sort; list entries in directory order
.
POSIX décrit -f
comme ceci:
forcer chaque argument à être interprété comme un répertoire et lister le nom trouvé dans chaque fente. Cette option doit s'éteindre
-l
,-t
,-s
et-r
, et doit tourner sur-a
; l'ordre est l'ordre dans lequel les entrées apparaissent dans le répertoire.
Commandes ls|wc -l
donner le mauvais résultat lorsque les noms de fichiers contiennent des newlines.
Dans zsh vous pouvez faire quelque chose comme ceci:
a=(*(DN));echo ${#a}
D
(glob_dots
) comprend les fichiers dont le nom commence par une période et N
(null_glob
) fait que la commande n'entraîne pas d'erreur dans un répertoire vide.
Ou même dans bash:
shopt -s dotglob nullglob;a=(*);echo ${#a[@]}
Si IFS
contient des chiffres ASCII, ajoutez des guillemets autour de ${#a[@]}
. Ajouter shopt -u failglob
pour s'assurer que failglob
n'est pas définie.
Une option portable est d'utiliser find
:
find . ! -name . -prune|grep -c /
grep -c /
peut être remplacé par wc -l
si les noms de fichiers ne contiennent pas de newlines. ! -name . -prune
est une alternative portable à -mindepth 1 -maxdepth 1
.
ou voici une autre alternative qui n'inclut pas habituellement les fichiers dont le nom commence par une période:
set -- *;[ -e "" ]&&echo "$#"
la commande ci-dessus inclut cependant les fichiers dont le nom commence par une période lorsqu'une option comme dotglob
en bash ou glob_dots
dans zsh est réglé. Lorsque *
ne correspond à aucun fichier, la commande entraîne une erreur dans zsh avec les paramètres par défaut.
j'ai utilisé cette commande..fonctionne comme un charme..seulement pour changer le maxdepth..c'est sous répertoires
find * -maxdepth 0 -type d -exec sh -c "echo -n {} ' ' ; ls -lR {} | wc -l" \;
je pense que vous pouvez avoir plus de contrôle sur ce à l'aide de find
:
find <path> -maxdepth 1 -type f -printf "." | wc -c
find -maxdepth 1
n'ira pas plus loin dans la hiérarchie des fichiers.-type f
permet de filtrer uniquement les fichiers. De même, vous pouvez utiliser-type d
pour les répertoires.-printf "."
imprime un point pour chaque match.wc -c
compte les caractères, donc il compte les points créés par leprint
... ce qui signifie compter combien de fichiers existent dans un fichier donné chemin.
autant Que je sache, il n'y a pas de meilleure alternative. Cette information pourrait être hors-sujet à cette question et vous pouvez déjà savoir que sous Linux (en général sous Unix) les répertoires sont juste un fichier spécial qui contient la liste des autres fichiers (je comprends que les détails exacts dépendra de système de fichiers spécifiques, mais c'est l'idée générale). Et il n'y a pas d'appel pour trouver le nombre total d'entrées sans traversant l'ensemble de la liste. S'il vous plaît, corrigez-moi si je me trompe.
Pour le nombre de fichiers dans un répertoire courant essayez ceci:
ls -lR * | wc -l