¿Cuál es la mejor manera de contar los resultados de "búsqueda"?

99

Mi solución actual sería find <expr> -exec printf '.' \; | wc -c, pero esto lleva demasiado tiempo cuando hay más de 10000 resultados. ¿No hay una forma mejor o más rápida de hacer esto?

MechMK1
fuente
use wc -l en sus resultados de búsqueda
Manuel Selva

Respuestas:

84

Intente esto en su lugar (requiera findel -printfsoporte):

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

Será más confiable y rápido que contar las líneas.

Tenga en cuenta que utilizo find's printf, no un comando externo.


Hagamos la banca un poco:

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

Mi punto de referencia de fragmentos:

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

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

Con líneas completas:

$ time find -type f | wc -l
8

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

Entonces mi solución es más rápida =) (la parte importante es la reallínea)

Gilles Quenot
fuente
6
No es equivalente, es más confiable =)
Gilles Quenot
6
No es más confiable si la marca -printf para buscar no es compatible con su plataforma. ;-)
Randy Howard
7
Tenga en cuenta que puede reducir algunos nanosegundos más sin citar el punto en-printf '.'
Jens
6
@Jens - especialmente cuando se tiene en cuenta el tiempo que se tarda en escribir eso
Brian Agnew
6
Con un punto de referencia tan pequeño, los tiempos probablemente estén dominados por otros factores además de lo que desea medir. Un experimento con un árbol grande sería más útil. Pero esto tiene mi voto para hacer realmente lo que pidió el OP.
tripleee
133

Por qué no

find <expr> | wc -l

como una simple solución portátil? Su solución original está generando un nuevo proceso printf para cada archivo individual encontrado, y eso es muy costoso (como acaba de descubrir).

Tenga en cuenta que esto contará en exceso si tiene nombres de archivo con nuevas líneas incrustadas, pero si tiene eso, sospecho que sus problemas son un poco más profundos.

Brian Agnew
fuente
9
-1: se romperá en el archivo con nuevas líneas, y es más lento que contar bytes =)
Gilles Quenot
21
No creo que eso justifique un voto negativo dado que la limitación de nombre de archivo / nueva línea es bastante rara y se indicó anteriormente. Más lento ? Quizás. Dado que está consultando un sistema de archivos, sospecho que la diferencia de velocidad es pequeña. En mis 10,000 archivos mido una diferencia de 3 ms
Brian Agnew
8
La diferencia de rendimiento entre 'find <expr> | wc -l' y 'find <expr> -printf. | wc -c 'son extremadamente pequeños. El almacenamiento en caché (es decir, si ejecuta la misma búsqueda dos veces sobre el mismo árbol) es mucho más importante. En mi humilde opinión, la solución con "wc -l" es mucho más intuitiva.
pitseeker
4

Esta es mi countfilesfunción en mi ~/.bashrc(es razonablemente rápida, debería funcionar para Linux y FreeBSD find, y no se deja engañar por las rutas de archivo que contienen caracteres de nueva línea; la final wcsolo cuenta bytes NUL):

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

countfiles

countfiles ~ '*.txt'
carlo
fuente
4

Esta solución es ciertamente más lenta que algunas de las otras find -> wcsoluciones aquí, pero si estuviera dispuesto a hacer algo más con los nombres de los archivos además de contarlos, podría hacerlo readdesde la findsalida.

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

Es solo una modificación de una solución que se encuentra en BashGuide que maneja correctamente archivos con nombres no estándar al hacer que el finddelimitador de salida sea un byte NUL usando print0y leyéndolo usando ''(byte NUL) como delimitador de bucle.

Juan B
fuente