¿Cómo combinar find y grep para una búsqueda compleja? (GNU / linux, find, grep)

17

Estoy tratando de hacer una búsqueda de texto en algunos archivos que comparten una estructura de directorio similar, pero no están en el mismo árbol de directorios, en GNU / Linux.

Tengo un servidor web con muchos sitios que comparten la misma estructura de árbol (marco PHP Code Igniter MVC), por lo que quiero buscar en un directorio específico en el árbol para cada sitio, por ejemplo:

/srv/www/*/htdocs/system/application/

Donde * es el nombre del sitio. Y desde esos directorios de aplicaciones , quiero buscar en todo el árbol hasta sus hojas, en busca de un archivo * .php que tenga algún patrón de texto adentro, digamos "debug (", no se necesita una expresión regular.

Sé cómo usar find y grep pero no soy bueno para combinarlos.

¿Cómo haría esto?
¡Gracias por adelantado!

Petruza
fuente

Respuestas:

21

Tratar

find /srv/www/*/htdocs/system/application/ -name "*.php" -exec grep "debug (" {} \; -print

Esto debería buscar de forma recursiva las carpetas en applicationbusca de archivos con .phpextensión y pasarlos a grep.

Una optimización en esto sería ejecutar:

find /srv/www/*/htdocs/system/application/ -name "*.php" -print0 | xargs -0 grep -H "debug ("

Esto sirve xargspara pasar todos los .phparchivos de salida findcomo argumentos a un solo grepcomando; por ejemplo, . La opción y la opción de garantizar que los espacios en los nombres de archivo y directorio se manejen correctamente. La opción pasada a garantiza que el nombre del archivo se imprima en todas las situaciones. (De forma predeterminada, imprime el nombre del archivo solo cuando se pasan varios argumentos).grep "debug (" file1 file2 file3-print0find-0xargs-Hgrepgrep

De hombre xargs:

-0

      Los elementos de entrada terminan con un carácter nulo en lugar de un espacio en blanco, y las comillas y la barra diagonal inversa no son especiales (cada carácter se toma literalmente). Deshabilita el final de la cadena del archivo, que se trata como cualquier otro argumento. Útil cuando los elementos de entrada pueden contener espacios en blanco, comillas o barras diagonales inversas. La -print0opción de búsqueda GNU produce una entrada adecuada para este modo.

nagul
fuente
1
+1. Sin embargo, eso ejecutará grep para cada archivo php. Si hay muchos archivos, puede optimizar aún másfind /srv/www/*/htdocs/system/application/ -name "*.php" -print0 | xargs -0 grep "debug ("
Jukka Matilainen
@jackem De acuerdo. Actualizaré mi respuesta en consecuencia.
nagul
2
Otra pequeña mejora: los xargs pueden pasar un nombre de archivo a grep, en cuyo caso grep no mostrará el nombre de archivo si hay una coincidencia. Es posible que desee agregar -H al comando grep para forzarlo a mostrar el nombre del archivo.
Randy Orrison
@Randy Ese es un punto muy válido.
nagul
3
Esto es una verdadera nigromancia, pero GNU findpuede tomar el +operador en lugar de \;realizar el mismo tipo de ejecución de proceso único que lo xargshace. Por lo tanto, find /srv/www/*/htdocs/system/application/ -name "*.php" -exec grep -H "debug (" {} +hace lo mismo que el xargsejemplo en esta respuesta, pero con una bifurcación de proceso menos (y aún 0 riesgo de problemas de nombre de archivo).
Daniel Andersson
10

findni siquiera es necesario para este ejemplo, uno puede usar grepdirectamente (al menos GNU grep):

grep -RH --include='*.php' "debug (" /srv/www/*/htdocs/system/application/

y nos quedamos con un solo tenedor de proceso.

Opciones:

  • -R, --dereference-recursive Read all files under each directory, recursively. Follow all symbolic links, unlike -r.
  • -H, --with-filename Print the file name for each match. This is the default when there is more than one file to search.
  • --include=GLOB Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).
  • --exclude=GLOB Skip any command-line file with a name suffix that matches the pattern GLOB, using wildcard matching; a name suffix is either the whole name, or any suffix starting after a / and before a +non-/. When searching recursively, skip any subfile whose base name matches GLOB; the base name is the part after the last /. A pattern can use *, ?, and [...] as wildcards, and \ to quote a wildcard or backslash character literally.
Daniel Andersson
fuente
Solo por curiosidad, ¿qué -RHsignifican las opciones?
Gus
@Gus: man grepExtracto agregado de descripciones de opciones a la publicación.
Daniel Andersson
0

Su shell puede encontrar los archivos php y dárselos a grep. En bash:

shopt -s nullglob globstar
grep searchterm /srv/www/*/htdocs/system/application/**/*.php
usuario2394284
fuente