¿Qué es más eficiente para encontrar qué archivos en un sistema de archivos completo contienen una cadena: grep recursivo o buscar con grep en una declaración ejecutiva? Supongo que encontrar sería más eficiente porque al menos puede hacer un filtrado si conoce la extensión del archivo o una expresión regular que coincida 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" {} \;

Comentarios

  • Matemáticas / ciencias de la computación / eficiencia de algoritmos ins ‘ t opinión basado.
  • Marque este. Aunque no es recursivo, daría una idea de cuál es mejor. unix.stackexchange.com/questions/47983/…
  • @AvinashRaj he ‘ s no pido opinión. Él ‘ ‘ pregunta cuál es más eficiente y / o más rápido , no cuál es » mejor «. Esta es una pregunta perfectamente respondible que tiene una única respuesta específica que depende de cómo estos dos programas hacen su trabajo y de qué les da exactamente para buscar.
  • Tenga en cuenta que el -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 las grep opciones para obtener exactamente salida equivalente.
  • Probablemente no ‘ no deseaba la opción -r en grep para el segundo

Responder

No estoy seguro:

grep -r -i "the brown dog" /* 

es realmente lo que quieres decir. Eso significaría grep recursivamente en todos los archivos y directorios no ocultos en / (pero aún busque dentro de los archivos y directorios ocultos dentro de ellos).

Suponiendo que quiso decir:

grep -r -i "the brown dog" / 

Algunas cosas a tener en cuenta:

  • No todas las grep admiten -r. Y entre los que lo hacen, los comportamientos difieren: algunos siguen enlaces simbólicos a directorios al atravesar el árbol de directorios (lo que significa que puede terminar buscando varias veces en el mismo archivo o incluso se ejecutan en bucles infinitos), algunos no lo harán. Algunos buscarán dentro de los archivos del dispositivo (y tomará bastante tiempo en /dev/zero por ejemplo) o tuberías o archivos binarios …, algunos no lo harán.
  • Es eficiente ya que grep comienza a buscar dentro de los archivos tan pronto como los descubre. Pero mientras busca en un archivo, ya no busca más archivos para buscar (lo que es probablemente igual de bien en la mayoría de los casos)

Su:

find / -type f -exec grep -i "the brown dog" {} \; 

(eliminado el -r que no tenía sentido aquí) es terriblemente ineficiente porque está ejecutando un grep por archivo. ; solo debe usarse para comandos que aceptan solo un argumento. Además, aquí, debido a que grep solo busca en un archivo, no imprimirá el nombre del archivo, por lo que «no sabrá dónde están las coincidencias». no está mirando dentro de archivos de dispositivo, canalizaciones, enlaces simbólicos …, no está siguiendo enlaces simbólicos, pero todavía está mirando dentro de cosas como /proc/mem.

find / -type f -exec grep -i "the brown dog" {} + 

sería mucho mejor porque se ejecutarían tan pocos grep comandos como sea posible. Obtendrá el nombre del archivo a menos que la última ejecución tenga solo un archivo. Para eso, es mejor usar:

find / -type f -exec grep -i "the brown dog" /dev/null {} + 

o con GNU grep:

find / -type f -exec grep -Hi "the brown dog" {} + 

Tenga en cuenta que grep no se iniciará hasta find ha encontrado suficientes archivos para masticar, por lo que habrá un retraso inicial. Y find no continuará buscando más archivos hasta que el grep anterior haya regresado. Asignar y pasar la lista de archivos grande tiene algún impacto (probablemente insignificante), por lo que, en general, probablemente sea menos eficiente que un grep -r que no sigue el enlace simbólico o mira dispositivos internos.

Con herramientas GNU:

find / -type f -print0 | xargs -r0 grep -Hi "the brown dog" 

Como se indicó anteriormente, tan solo unos grep Se ejecutarán las instancias posibles, pero find continuará buscando más archivos mientras la primera grep invocación busca dentro del primer lote. Sin embargo, eso puede ser una ventaja o no.Por ejemplo, con los datos almacenados en discos duros rotativos, find y grep acceder a los datos almacenados en diferentes ubicaciones del disco ralentizará el disco. rendimiento haciendo que la cabeza del disco se mueva constantemente. En una configuración RAID (donde find y grep pueden 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 puede mejorar las cosas. Aún con herramientas GNU en almacenamiento RAID1 con 3 discos,

find / -type f -print0 | xargs -r0 -P2 grep -Hi "the brown dog" 

podría aumentar el rendimiento de manera significativa. Sin embargo, tenga en cuenta que el segundo grep solo se iniciará una vez que se hayan encontrado suficientes archivos para completar el primer grep comando. Puede agregar una opción -n a xargs para que eso suceda antes (y pasar menos archivos por grep invocación).

También tenga en cuenta que si «está redirigiendo la salida xargs a cualquier cosa que no sea un dispositivo terminal, entonces greps s comenzará a almacenar en búfer su salida, lo que significa que la salida de esos grep s probablemente se intercalará incorrectamente. Debería utilizar stdbuf -oL (donde esté disponible, como en GNU o FreeBSD) en ellos para solucionarlo (es posible que aún tenga problemas con líneas muy largas (típicamente> 4 KB)) o haga que cada uno escriba su salida en un archivo separado y concatenelos todos al final.

Aquí, la cadena que estás buscando es fija (no una expresión regular), por lo que usar la opción -F podría marcar la diferencia (poco probable ya que grep las implementaciones ya saben cómo optimizar eso).

Otra cosa que podría Haría una gran diferencia si fija la configuración regional en C si «se encuentra en una configuración regional de varios bytes:

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog" 

Para evitar mirar dentro /proc, /sys …, use -xdev y especifique los sistemas de archivos en los que desea buscar:

LC_ALL=C find / /home -xdev -type f -exec grep -i "the brown dog" /dev/null {} + 

O pode las rutas que desea excluir explícitamente:

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \ -type f -exec grep -i "the brown dog" /dev/null {} + 

Comentarios

  • No ‘ supongo que alguien puede señalarme un recurso – o explicar – qué {} y + significan. No hay ‘ nada que pueda ver en las páginas de manual para exec, grep o find en el cuadro de Solaris que ‘ estoy usando. ¿Es solo el shell concatenando nombres de archivos y pasándolos a grep?
  • @Poldie, eso ‘ se explica claramente en la descripción de -exec predicado en la página de manual de Solaris
  • Ah, sí. No estaba ‘ t escapando de mi {char mientras buscaba en la página del manual. Tu enlace es mejor; Me parece terrible leer las páginas de manual.
  • ¿RAID1 con 3 discos? Qué extraño …
  • @tink, sí, RAID1 está en 2 o más discos. Con 3 discos en comparación con 2 discos, aumenta la redundancia y el rendimiento de lectura, mientras que el rendimiento de escritura es aproximadamente el mismo. Con 3 discos en lugar de 2, eso significa que también puede corregir errores, ya que cuando un bit voltea en una de las copias, ‘ puede saber cuál es el correcto marcando todos 3 copias, mientras que con 2 discos, no puede ‘ realmente decirlo.

Responder

Si el * en la llamada grep no es importante para usted, entonces el primero debería ser más eficiente ya que solo uno Se inicia una instancia de grep, y las bifurcaciones no son gratuitas. En la mayoría de los casos, será más rápido incluso con * pero en casos extremos la clasificación podría revertir eso.

Puede haber otras findgrep estructuras que funcionan mejor, especialmente con muchas estructuras pequeñas archivos. Leer grandes cantidades de entradas de archivos e inodos a la vez puede mejorar el rendimiento en medios rotativos.

Pero echemos un vistazo a las estadísticas de syscall:

buscar

> strace -cf find . -type f -exec grep -i -r "the brown dog" {} \; % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97.86 0.883000 3619 244 wait4 0.53 0.004809 1 9318 4658 open 0.46 0.004165 1 6875 mmap 0.28 0.002555 3 977 732 execve 0.19 0.001677 2 980 735 stat 0.15 0.001366 1 1966 mprotect 0.09 0.000837 0 1820 read 0.09 0.000784 0 5647 close 0.07 0.000604 0 5215 fstat 0.06 0.000537 1 493 munmap 0.05 0.000465 2 244 clone 0.04 0.000356 1 245 245 access 0.03 0.000287 2 134 newfstatat 0.03 0.000235 1 312 openat 0.02 0.000193 0 743 brk 0.01 0.000082 0 245 arch_prctl 0.01 0.000050 0 134 getdents 0.00 0.000045 0 245 futex 0.00 0.000041 0 491 rt_sigaction 0.00 0.000041 0 246 getrlimit 0.00 0.000040 0 489 244 ioctl 0.00 0.000038 0 591 fcntl 0.00 0.000028 0 204 188 lseek 0.00 0.000024 0 489 set_robust_list 0.00 0.000013 0 245 rt_sigprocmask 0.00 0.000012 0 245 set_tid_address 0.00 0.000000 0 1 uname 0.00 0.000000 0 245 fchdir 0.00 0.000000 0 2 1 statfs ------ ----------- ----------- --------- --------- ---------------- 100.00 0.902284 39085 6803 total 

solo grep

> strace -cf grep -r -i "the brown dog" . % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 40.00 0.000304 2 134 getdents 31.71 0.000241 0 533 read 18.82 0.000143 0 319 6 openat 4.08 0.000031 4 8 mprotect 3.29 0.000025 0 199 193 lseek 2.11 0.000016 0 401 close 0.00 0.000000 0 38 19 open 0.00 0.000000 0 6 3 stat 0.00 0.000000 0 333 fstat 0.00 0.000000 0 32 mmap 0.00 0.000000 0 4 munmap 0.00 0.000000 0 6 brk 0.00 0.000000 0 2 rt_sigaction 0.00 0.000000 0 1 rt_sigprocmask 0.00 0.000000 0 245 244 ioctl 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 execve 0.00 0.000000 0 471 fcntl 0.00 0.000000 0 1 getrlimit 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 1 futex 0.00 0.000000 0 1 set_tid_address 0.00 0.000000 0 132 newfstatat 0.00 0.000000 0 1 set_robust_list ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000760 2871 466 total 

Comentarios

  • En la escala de búsqueda de un sistema de archivos completo, las bifurcaciones son insignificantes. E / S es lo que desea reducir.
  • Aunque es un error del OP, la comparación es incorrecta, debe eliminar el indicador -r de grep cuando se usa find. Puede ver que buscó una y otra vez los mismos archivos comparando el número de open que sucedieron.
  • @qwertzguy, no, el -r debe ser inofensivo ya que el -type f garantiza que ninguno de los argumentos son directorios. Es más probable que los múltiples open() s se reduzcan a los otros archivos abiertos por grep en cada invocación (bibliotecas, datos de localización …) ( gracias por editar mi respuesta por cierto)

Responder

Si estás en un SSD y buscas tiempo es insignificante, podría usar GNU paralelo:

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} " 

Esto ejecutará hasta 8 procesos grep al mismo tiempo basado en lo que find encontrado.

Esto estropeará una unidad de disco duro, pero una SSD debería funcionar bastante bien.

Respuesta

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 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 buscar es definitivamente el camino a seguir desde ciertas versiones de grep bombardeará con un error Lista de argumentos demasiado larga cuando llegue a un directorio con más archivos que el máximo de archivos abiertos maneja la configuración.

Solo mis 2 ¢.

Comentarios

  • ¿Por qué grep ¿bomba? Al menos con GNU grep si proporciona una ruta con / final y la usa -R ‘ Simplemente iteraré a través de los directorios. El shell no ‘ t va a expandir nada a menos que le proporcione shell-globs. Entonces, en el ejemplo dado (/*) solo importa el contenido de /, no de las subcarpetas que simplemente serán enumeradas por grep, no se pasa como argumento desde el shell.
  • Bueno, considerando que el OP estaba preguntando acerca de la búsqueda recursiva (por ejemplo, » grep -r -i ‘ el perro marrón ‘ / * «), he visto GNU ‘ s grep (al menos la versión 2.9) bombardea con: » -bash: / bin / grep: Lista de argumentos demasiado larga » usando la búsqueda exacta que el OP usó en un directorio que tenía más de 140,000 subdirectorios en él.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *