Quelle est la meilleure façon de compter les résultats de «recherche»?

99

Ma solution actuelle serait find <expr> -exec printf '.' \; | wc -c, mais cela prend beaucoup trop de temps quand il y a plus de 10000 résultats. N'y a-t-il pas de moyen plus rapide / meilleur de le faire?

MechMK1
la source
utilisez wc -l sur vos résultats de recherche
Manuel Selva

Réponses:

84

Essayez plutôt ceci (nécessite findle -printfsupport de):

find <expr> -type f -printf '.' | wc -c

Ce sera plus fiable et plus rapide que de compter les lignes.

Notez que j'utilise le find's printf, pas une commande externe.


Bancons un peu:

$ ls -1
a
e
l
ll.sh
r
t
y
z

Mon benchmark d'extrait:

$ time find -type f -printf '.' | wc -c
8

real    0m0.004s
user    0m0.000s
sys     0m0.007s

Avec des lignes complètes:

$ time find -type f | wc -l
8

real    0m0.006s
user    0m0.003s
sys     0m0.000s

Donc ma solution est plus rapide =) (la partie importante est la realligne)

Gilles Quenot
la source
6
Pas équivalent, c'est plus fiable =)
Gilles Quenot
6
Ce n'est pas plus fiable si l'indicateur -printf à rechercher n'est pas pris en charge sur votre plate-forme. ;-)
Randy Howard
7
Notez que vous pouvez réduire quelques nanosecondes de plus en ne citant pas le point dans-printf '.'
Jens
6
@Jens - surtout quand on prend en compte le temps nécessaire pour taper ça
Brian Agnew
6
Avec un si petit indice de référence, les délais sont probablement dominés par d'autres facteurs que ce que vous voulez mesurer. Une expérience avec un grand arbre serait plus utile. Mais cela me vaut mon vote pour faire ce que le PO a demandé.
tripleee
132

Pourquoi pas

find <expr> | wc -l

comme une simple solution portable? Votre solution d'origine génère un nouveau processus printf pour chaque fichier individuel trouvé, et cela coûte très cher (comme vous venez de le trouver).

Notez que cela surclassera si vous avez des noms de fichiers avec des nouvelles lignes intégrées, mais si vous l'avez, je soupçonne que vos problèmes sont un peu plus profonds.

Brian Agnew
la source
9
-1: se cassera sur le fichier avec les retours à la ligne, et c'est plus lent que de compter les octets =)
Gilles Quenot
21
Je ne pense pas que cela justifie un vote défavorable étant donné que la limitation du nom de fichier / nouvelle ligne est assez rare et notée ci-dessus. Ralentissez ? Peut-être. Étant donné que vous interrogez un système de fichiers, je soupçonne que la différence de vitesse est faible. Sur mes 10000 fichiers, je mesure une différence de 3 ms
Brian Agnew
8
La différence de performances entre 'find <expr> | wc -l' et 'find <expr> -printf. | wc -c 'sont extrêmement petits. La mise en cache (c'est-à-dire si vous exécutez la même recherche deux fois sur le même arbre) est beaucoup plus importante. IMHO la solution avec "wc -l" est beaucoup plus intuitive.
pitseeker
4

Cette solution est certainement plus lente que certaines des autres find -> wcsolutions ici, mais si vous étiez enclin à faire autre chose avec les noms de fichiers en plus de les compter, vous pourriez le faire à readpartir de la findsortie.

n=0
while read -r -d ''; do
    ((n++)) # count
    # maybe perform another act on file
done < <(find <expr> -print0)
echo $n

Il s'agit simplement d'une modification d' une solution trouvée dans BashGuide qui gère correctement les fichiers avec des noms non standard en faisant du finddélimiteur de sortie un octet NUL en utilisant print0et en lisant en utilisant ''(octet NUL) comme délimiteur de boucle.

John B
la source
3

C'est ma countfilesfonction dans mon ~/.bashrc(c'est raisonnablement rapide, devrait fonctionner pour Linux et FreeBSD find, et ne se laisse pas berner par les chemins de fichiers contenant des caractères de nouvelle ligne; le final wcne compte que les octets NUL):

countfiles () 
{ 
   command find "${1:-.}" -type f -name "${2:-*}" -print0 | 
       command tr -dc '\0' | command wc -c;
return 0
}

countfiles

countfiles ~ '*.txt'
carlo
la source