¿Qué es más eficiente para encontrar qué archivos en un sistema de archivos completo contienen una cadena: grep recursiva o encontrar con grep en una declaración ejecutiva? Supongo que find sería más eficiente porque al menos puede filtrar si conoce la extensión del archivo o una expresión regular que coincide con el nombre del archivo, pero cuando solo sabe -type f
cuál es mejor. GNU grep 2.6.3; find (GNU findutils) 4.4.2
Ejemplo:
grep -r -i 'the brown dog' /
find / -type f -exec grep -i 'the brown dog' {} \;
-exec {} +
formulario hará menos bifurcaciones, por lo que debería ser más rápido que-exec {} \;
. Es posible que deba agregar-H
(o-h
) a lasgrep
opciones para obtener un resultado exactamente equivalente.-r
opcióngrep
para la segundaRespuestas:
No estoy seguro:
es realmente lo que quisiste decir. Eso significaría grep recursivamente en todos los archivos y directorios no ocultos
/
(pero aún mira dentro de los archivos y directorios ocultos dentro de ellos).Suponiendo que quisieras decir:
Algunas cosas a tener en cuenta:
grep
implementaciones son compatibles-r
. Y entre los que lo hacen, los comportamientos difieren: algunos siguen enlaces simbólicos a directorios cuando atraviesan el árbol de directorios (lo que significa que puede terminar buscando varias veces en el mismo archivo o incluso ejecutarse en bucles infinitos), otros no. Algunos buscarán dentro de los archivos del dispositivo (y llevará bastante tiempo,/dev/zero
por ejemplo) o tuberías o archivos binarios ..., otros no.grep
comienza a buscar dentro de los archivos tan pronto como los descubre. Pero mientras se ve en un archivo, ya no busca más archivos para buscar (lo que probablemente sea igual de bueno en la mayoría de los casos)Tu:
(eliminado el
-r
que no tenía sentido aquí) es terriblemente ineficiente porque está ejecutando unogrep
por archivo.;
solo debe usarse para comandos que aceptan solo un argumento. Además, aquí, debido a quegrep
solo se ve en un archivo, no imprimirá el nombre del archivo, por lo que no sabrá dónde están las coincidencias.No estás buscando dentro de los archivos del dispositivo, tuberías, enlaces simbólicos ..., no estás siguiendo los enlaces simbólicos, pero aún estás potencialmente buscando cosas como
/proc/mem
.sería mucho mejor porque
grep
se ejecutarían la menor cantidad de comandos posible. Obtendría el nombre del archivo a menos que la última ejecución tenga solo un archivo. Para eso es mejor usar:o con GNU
grep
:Tenga en cuenta que
grep
no se iniciará hasta quefind
haya encontrado suficientes archivos para masticar, por lo que habrá un retraso inicial. Yfind
no continuará buscando más archivos hasta que el anteriorgrep
haya regresado. La asignación y aprobación de la lista de archivos grandes tiene un impacto (probablemente insignificante), por lo que, en general, será menos eficiente que ungrep -r
enlace simbólico o que no mire dentro de los dispositivos.Con herramientas GNU:
Como se indicó anteriormente,
grep
se ejecutarán la menor cantidad posible de instancias, perofind
continuarán buscando más archivos mientras la primeragrep
invocación se encuentra dentro del primer lote. Sin embargo, eso puede o no ser una ventaja. Por ejemplo, con los datos almacenados en discos duros rotativos,find
y elgrep
acceso a los datos almacenados en diferentes ubicaciones del disco disminuirá el rendimiento del disco al hacer que el cabezal del disco se mueva constantemente. En una configuración RAID (dondefind
ygrep
puede acceder a diferentes discos) o en SSD, eso podría marcar una diferencia positiva.En una configuración RAID, ejecutar varias invocaciones concurrentes
grep
también podría mejorar las cosas. Aún con herramientas GNU en almacenamiento RAID1 con 3 discos,podría aumentar el rendimiento significativamente. Sin embargo,
grep
tenga en cuenta que el segundo solo se iniciará una vez que se hayan encontrado suficientes archivos para completar el primergrep
comando. Puede agregar una-n
opciónxargs
para que eso suceda antes (y pasar menos archivos porgrep
invocación).También tenga en cuenta que si está redirigiendo la
xargs
salida a cualquier cosa que no sea un dispositivo terminal, entonces losgreps
s comenzarán a almacenar en búfer su salida, lo que significa que la salida de esosgrep
s probablemente se entrelazará incorrectamente. Tendría que usarstdbuf -oL
(cuando esté disponible, como en GNU o FreeBSD) en ellos para solucionarlo (aún puede tener problemas con líneas muy largas (generalmente> 4KiB)) o hacer que cada uno escriba su salida en un archivo separado y los concatene todo al final.Aquí, la cadena que está buscando es fija (no es una expresión regular), por lo que usar la
-F
opción puede hacer la diferencia (es poco probable ya que lasgrep
implementaciones ya saben cómo optimizar eso).Otra cosa que podría marcar una gran diferencia es arreglar la configuración regional en C si está en una configuración regional de varios bytes:
Para evitar mirar dentro
/proc
,/sys
..., use-xdev
y especifique los sistemas de archivos en los que desea buscar:O pode los caminos que desea excluir explícitamente:
fuente
-exec
predicado en la página de manual de SolarisSi el
*
de lagrep
llamada no es importante para ti, entonces el primero debe ser más eficiente ya que sólo una instancia degrep
que se inicie, y horquillas no son libres. En la mayoría de los casos, será más rápido incluso con el caso,*
pero en casos extremos, la clasificación podría revertir eso.Puede haber otros
find
-grep
estructuras que funcionan mejor, especialmente con muchos archivos pequeños. La lectura de grandes cantidades de entradas de archivo e inodos a la vez puede mejorar el rendimiento de los medios rotativos.Pero echemos un vistazo a las estadísticas de syscall:
encontrar
solo grep
fuente
-r
indicador degrep
cuando se usafind
. Puede ver que buscó una y otra vez los mismos archivos al comparar el número de loopen
sucedido.-r
debería ser inofensivo ya que las-type f
garantías de que ninguno de los argumentos son directorios. Los múltiplesopen()
s son más probables hasta los otros archivos abiertos porgrep
cada invocación (bibliotecas, datos de localización ...) (gracias por la edición en mi respuesta por cierto)Si está en un SSD y el tiempo de búsqueda es insignificante, podría usar GNU paralelo:
Esto ejecutará hasta 8 procesos grep al mismo tiempo según lo
find
encontrado.Esto golpeará una unidad de disco duro, pero un SSD debería hacer frente bastante bien.
fuente
Una cosa más a considerar en este caso es la siguiente.
¿Alguno de los directorios por los que grep tendrá que pasar recursivamente contendrá más archivos que la configuración de nofile de su sistema ? (por ejemplo, número de identificadores de archivos abiertos, el valor predeterminado es 1024 en la mayoría de las distribuciones de Linux)
Si es así, entonces encontrar es definitivamente el camino a seguir, ya que ciertas versiones de grep bombardearán con un error de lista de argumentos demasiado largo cuando llegue a un directorio con más archivos que la configuración máxima de identificadores de archivos abiertos.
Solo mi 2 ¢.
fuente
grep
bombardear? Al menos con GNU grep si le das una ruta con el rastreo/
y la usas-R
simplemente iterará a través de los directorios. El caparazón no va a expandir nada a menos que le des globs. Entonces, en el ejemplo dado (/*
) solo los contenidos de la/
materia, no de las subcarpetas que simplemente se enumerarángrep
, no se pasarán como argumento desde el shell.