Quelle est la meilleure façon de compter le nombre de fichiers dans un répertoire?


11

Si l'analyse de la sortie de lsest dangereuse car elle peut casser certains caractères géniaux (espaces,, \n...), quelle est la meilleure façon de connaître le nombre de fichiers dans un répertoire?

Je compte généralement sur findpour éviter cette analyse, mais de la même manière, il find mydir | wc -lse cassera pour les mêmes raisons.

Je travaille sur Solaris en ce moment, mais je cherche une réponse aussi portable sur différents unices et différents shells que possible.


3
Je ne suis pas sûr que ce soit un doublon, est-ce que je manque quelque chose?
rahmu

1
Il peut s'agir d'un doublon, mais pas de la question indiquée. findvous obtiendrez le nombre de fichiers récursivement (utilisez -maxdepth 1si vous ne le souhaitez pas. find mydir -maxdepth 1 -type f -printf \\n | wc -ldevrait gérer les caractères spéciaux dans le nom de fichier, car ils ne sont jamais imprimés en premier lieu.
Anthon

Réponses:


15

Et cette astuce?

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

Aussi portable que findet wc.


5
Cela ne fonctionne pas (il affiche des n+1fichiers sur mon système Debian). Il ne filtre pas non plus les fichiers normaux.
Chris Down

4
Je viens de donner un exemple générique. Il fonctionne, mais comment cela fonctionne dépend de la façon dont vous adaptez la findcommande à vos besoins spécifiques. Oui, celui-ci inclut tous les répertoires, y compris .(ce qui pourrait être la raison pour laquelle vous voyez le résultat n+1).
rozcietrzewiacz

J'aime ce truc, très intelligent; mais je suis surpris qu'il n'y ait pas de façon simple et simple de le faire!
rahmu

3
@ChrisDown l'OP ne spécifie pas le filtrage pour les fichiers normaux, demande le nombre de fichiers dans un répertoire. Pour vous débarrasser du problème n + 1, utilisez find . -maxdepth 1 ! -name . -exec echo \; | wc -l; certaines anciennes versions findn'en ont pas -not.
Arcege

3
Notez que ce -maxdepthn'est pas standard (une extension GNU est désormais également prise en charge par quelques autres implémentations).
Stéphane Chazelas

11

Avec bash, sans utilitaires externes, ni boucles:

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

Dans ksh, remplacez shopt -s dotglobpar FIGNORE=.?(.). Dans zsh, remplacez-le par setopt glob_dotsou supprimez l' shoptappel et utilisez files=(*(D)). (Ou laissez simplement tomber la ligne si vous ne voulez pas inclure de fichiers dot.) Portablement, si vous ne vous souciez pas des fichiers dot:

set -- *
echo $#

Si vous souhaitez inclure des fichiers 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
Le premier exemple s'imprime 1pour un répertoire vide lorsque nullglobn'est pas activé. En zsh, a=(*(DN));echo ${#a}avec le qualificatif N( nullglob) n'entraîne pas d'erreur pour un répertoire vide.
nisetama

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

Devrait être assez portable pour les systèmes post-80.

Cela compte toutes les entrées du répertoire sauf .et ..dans le répertoire courant.

Pour compter également les fichiers dans les sous-répertoires:

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

(que l'on devrait être portable même sous Unix V6 (1975), car il n'en a pas besoin -prune)


L'une des rares réponses portables sur cette page, si ce n'est la seule.
xhienne

J'ai voté pour cette réponse hier car j'ai trouvé que cela fonctionne aussi bien pour les répertoires autres que le répertoire actuel ( find dirname ! -name dirname -prune -print). Je me suis depuis demandé s'il y avait une raison particulière d'utiliser à la grep -c /place de wc -l(qui est probablement plus couramment utilisé pour le comptage).
Anthony Geoghegan

1
find dirname ! -name dirnamene fonctionne pas s'il y a d'autres répertoires nommés dirname. Il vaut mieux l'utiliser find dirname/. ! -name .. wc -lcompte le nombre de lignes, les noms de fichiers peuvent être constitués de plusieurs lignes car le caractère de nouvelle ligne est aussi valide que n'importe quel autre dans un nom de fichier.
Stéphane Chazelas

6

Essayer:

ls -b1A | wc -l

Le -baura des caractères non imprimables, -Aaffichera tous les fichiers sauf .et ..et un par ligne (la valeur par défaut sur un canal, mais bon d'être explicite).

Tant que nous incluons des langages de script de niveau supérieur, voici une ligne unique en Python:

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

Ou avec une «recherche» complète:

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

1

Yoc peut utiliser une telle construction:

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

Mais j'ai bien peur, vous pouvez commettre une erreur comme Argument list too long.si vous avez trop de fichiers dans le répertoire. Cependant, je l'ai testé sur un répertoire avec 10 milliards de fichiers, et cela a bien fonctionné.


3
Cela ne fonctionnera pas non plus pour les fichiers cachés, sauf si le shell est configuré pour étendre ceux avec *.
Lekensteyn

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

4
@Rush: cette commande ne devrait jamais déclencher "arg list too long". Cela ne se produit qu'avec une commande externe (donc jamais avec for.
enzotib

1

Avez-vous pensé à Perl, qui devrait être relativement portable?

Quelque chose comme:

use File::Find;

$counter = 0;

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

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

0

Essayez ceci => Utilisation de ls avec les options -i (pour le numéro de nœud) et -F (ajoute le nom du répertoire avec '/').

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

0

Avec une perldoublure (reformatée pour plus de lisibilité):

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

ou

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

Vous pouvez utiliser des perlfonctions qui modifient des tableaux comme grepou mapavec la deuxième version. Voir perldoc -f readdirpour un exemple d'utilisation grep.


0

La version la plus simple que j'utilise tout le temps et avec laquelle je n'ai jamais eu de problème est: ls -b1 | wc -l


Vous pourriez rencontrer des problèmes si le nom du fichier contient un \nou d'autres caractères géniaux (oui, certains unités le permettent).
rahmu

1
J'ai essayé cela explicitement avant de poster ma réponse et je n'ai eu aucun problème avec cela. J'ai utilisé le gestionnaire de fichiers nautilus pour renommer un fichier à contenir \ n pour essayer cela.
Peter

Tu as raison, ça ne marche pas comme ça. Je ne sais pas ce que j'ai fait lors de mon premier test. J'ai essayé à nouveau et mis à jour ma réponse.
Peter

Non, la commande est OK, mais il existe déjà une solution similaire et les fichiers cachés ne sont pas comptés.
xhienne

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.