¿Hay una manera más simple de grep todos los archivos en un directorio?

21

Cuando quiero buscar contenido en un árbol completo, uso

find . -type f -print0 | xargs -0 grep <search_string>

¿Hay una mejor manera de hacer esto en términos de rendimiento o brevedad?

Dancrumb
fuente
2
@Downvoter: feliz de mejorar esta pregunta si puede compartir sus inquietudes.
Dancrumb
2
muchas versiones de búsqueda tienen xargs integrados: buscar. -type f -exec fgrep <search_string> {} +
simpleuser

Respuestas:

42

Verifique si su opción de grepsoporte -r(para recurse ):

grep -r <search_string> .
Philippos
fuente
1
Sí ... acabo de encontrar stackoverflow.com/questions/16956810/... y esa es la respuesta allí también.
Dancrumb
¡agregue un comentario --exclude-dirpara abordar el rendimiento y tenemos un ganador!
Dancrumb
1
Solo tenga en cuenta que esto no es portátil, sin embargo, grepen las recientes distribuciones de FreeBSD y Linux lo admiten. Y por qué --exclude-dir? ¿No pediste buscar un árbol entero ?
Philippos
El punto justo ... --exclude-dires realmente útil en mi caso de uso (porque partes del subárbol son grandes, pero inútiles) y pregunté sobre el rendimiento ... pero tienes razón, no es necesario.
Dancrumb
En este caso, debo agregar que IIRC --exclude-dires exclusivo de GNU grep. (-:
Philippos
13

Una respuesta subóptima: en lugar de canalizar la salida de finden grep, simplemente podría ejecutar

find . -type f -exec grep 'research' {} '+'

y listo, un comando en lugar de dos!

explicación:

find . -type f

encuentra todos los archivos regulares dentro.

-exec grep 'research'

grep 'investigación'

{}

en nombre de archivo encontrado

'+'

use un comando por todos los nombres de archivo, no una vez por nombre de archivo.

Nb: con ';'esto hubiera sido una vez por nombre de archivo.

Aparte de eso, si usa eso para procesar el código fuente, puede investigar ack, que está hecho para buscar bits de código fácilmente.

ack

Editar:

Puedes extender esa investigación un poco. Primero, puede usar el -name ''interruptor de findpara buscar archivos con un patrón de nomenclatura específico.

Por ejemplo :

  • solo archivos que corresponden a registros: -name '*.log'

  • solo archivos que corresponden a encabezados c, pero no puede seguir con mayúsculas o minúsculas para sus extensiones de nombre de archivo: -iname *.c

Nb: como para grepy ack, el -iinterruptor significa mayúsculas y minúsculas en este caso.

En ese caso, grep se mostrará sin color y sin números de línea.

Puede cambiar eso con el --colory los -ninterruptores (números de color y líneas en los archivos, respectivamente).

Al final, puedes tener algo como:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

por ejemplo

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello
Pierre-Antoine Guillaume
fuente
55
ackes genial, y una versión más rápida de ackis ag(el buscador de plata, geoff.greer.fm/ag )
cfeduke
1
Prefiero esto con filtro como -name '*.log'es más rápido.
sdkks
@cfeduke No lo he probado, principalmente porque ag no es parte de los repositorios de apt predeterminados en WSL (¡tienes que trabajar con lo que tienes!)
Pierre-Antoine Guillaume
Un truco es agregar / dev / null al grep para que aparezca el nombre del archivo.
ChuckCottrill
Un truco es buscar solo directorios y luego -exec grep / dev / null {} / * para obtener todos los archivos con un solo fork / exec por directorio.
ChuckCottrill
12

Si desea recurrir a subdirectorios:

grep -R 'pattern' .

La -Ropción no es una opción estándar, pero es compatible con las grepimplementaciones más comunes .

Kusalananda
fuente
77
Use en -rlugar de -Romitir enlaces simbólicos cuando se trate de GNU grep
α --sнιη
1
@AFSHIN ¿Por qué no querrías seguir enlaces simbólicos?
Kusalananda
44
@Kusalananda Recursion? Aunque las grepimplementaciones actuales de GNU atrapan recursiones, creo. De lo contrario, depende de lo que quiere decir con "árbol".
Philippos
2
@Philippos en mi humilde opinión, cuidar a los usuarios no es algo que una herramienta grepdebería hacer. Si el usuario tiene bucles de enlace simbólico en su estructura de directorio, bueno, ese es el problema del usuario :-)
Kusalananda
3
@Kusalananda ¿Y si el sistema proporciona el bucle? Nunca me perdí en /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI como herramientas que me cuidan (a menos que proporcionen magia extraña que llaman "AI"). (-;
Philippos
5

Como se señaló anteriormente -ro -R(dependiendo del manejo deseado del enlace simbólico) es una opción rápida.

Sin embargo, -d <action>puede ser útil a veces.

Lo bueno -des el comando de omisión, que silencia el "grep: nombre_directorio: es un directorio" cuando solo quiere escanear el nivel actual.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

y por supuesto:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

La -d skipopción es REALMENTE útil dentro de otro script para que no tenga que hacerlo 2> /dev/null. :)

Petro
fuente
0

Si se trata de una gran cantidad de archivos, el grep se ejecuta más rápido si poda los archivos que necesita buscar en lugar de agrupar todos los archivos en subcarpetas.

A veces uso este formato:

grep "primary" `find . | grep cpp$`

Encuentra todos los archivos en subcarpetas de .ese final en cpp. Luego grep esos archivos para "primario".

Si lo desea, puede seguir canalizando esos resultados en otras llamadas grep:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"
Rudy
fuente
1
los backtics no son una buena práctica moderna, son casi obsoletos
Christopher
1
Esto se romperá si tiene archivos con caracteres especiales en sus nombres. No sé cuán especiales tienen que ser para ser demasiado especiales para que esto funcione tal como está, pero lo que estás haciendo es realmente lo mismo que analizar la salida de ls, que también es malo.
un CVn