Grep lo más rápido posible

Me gustaría saber si hay algún consejo para hacer grep más rápido posible. Tengo una base bastante grande de archivos de texto para buscar de la manera más rápida posible. Las hice minúsculas, para poder deshacerme de la opción -i . Esto hace que la búsqueda sea mucho más rápida.

Además, descubrí que los modos -F y -P son más rápidos que el predeterminado. Utilizo el primero cuando la cadena de búsqueda no es una expresión regular (solo texto simple), esta última si está involucrada la expresión regular.

¿Alguien tiene alguna experiencia en acelerar grep ? Tal vez comstackrlo desde cero con alguna bandera en particular (estoy en Linux CentOS), organizar los archivos de cierta manera o tal vez hacer la búsqueda paralela de alguna manera?

Pruebe con GNU parallel , que incluye un ejemplo de cómo usarlo con grep :

grep -r recursivamente a través de directorios. En las CPU multinúcleo GNU parallel menudo puede acelerar esto.

 find . -type f | parallel -k -j150% -n 1000 -m grep -H -n STRING {} 

Esto ejecutará 1.5 trabajos por núcleo y dará 1000 argumentos a grep .

Para archivos grandes, puede dividir la entrada en varios fragmentos con los argumentos --pipe y --block :

  parallel --pipe --block 2M grep foo < bigfile 

También puede ejecutarlo en varias máquinas diferentes a través de SSH (se necesita el agente ssh para evitar las contraseñas):

 parallel --pipe --sshlogin server.example.com,server2.example.net grep foo < bigfile 

Si está buscando archivos muy grandes, entonces establecer su configuración regional realmente puede ayudar.

GNU grep va mucho más rápido en la configuración regional C que con UTF-8.

 export LC_ALL=C 

Ripgrep afirma que ahora es el más rápido.

https://github.com/BurntSushi/ripgrep

También incluye el paralelismo por defecto

  -j, --threads ARG The number of threads to use. Defaults to the number of logical CPUs (capped at 6). [default: 0] 

Del README

Está construido sobre el motor de expresiones regulares de Rust. El motor de expresiones regulares de Rust utiliza autómatas finitos, SIMD y optimizaciones literales agresivas para realizar búsquedas muy rápido.

Al parecer, usar –mmap puede ayudar en algunos sistemas:

http://lists.freebsd.org/pipermail/freebsd-current/2010-August/019310.html

No es estrictamente una mejora de código, pero algo que encontré útil después de ejecutar grep en más de 2 millones de archivos.

Trasladé la operación a una unidad SSD barata (120 GB). Con aproximadamente $ 100, es una opción asequible si está procesando muchos archivos regularmente.

Si no le importa qué archivos contienen la cadena, es posible que desee separar la lectura y la división en dos trabajos, ya que puede ser costoso generar grep muchas veces, una para cada archivo pequeño.

  1. Si tienes un archivo muy grande:

    parallel -j100% --pipepart --block 100M -a grep <...>

  2. Muchos pequeños archivos comprimidos (ordenados por inode)

    ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j80% --group "gzcat {}" | parallel -j50% --pipe --round-robin -u -N1000 grep <..>

Normalmente comprime mis archivos con lz4 para un rendimiento máximo.

  1. Si solo quieres el nombre del archivo con la coincidencia:

    ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j100% --group "gzcat {} | grep -lq <..> && echo {}

Sobre la base de la respuesta de Sandro, miré la referencia que proporcionó aquí y jugué con BSD grep vs. GNU grep. Mis rápidos resultados de referencia mostraron: GNU grep es mucho más rápido.

Así que mi recomendación para la pregunta original “grep posible más rápido”: asegúrese de que está utilizando GNU grep en lugar de BSD grep (que es el predeterminado en MacOS, por ejemplo).

Yo personalmente uso el ag (buscador de plata) en lugar de grep y es mucho más rápido, también puedes combinarlo con un bloque paralelo y de tubería.

https://github.com/ggreer/the_silver_searcher

Actualización: ahora uso https://github.com/BurntSushi/ripgrep que es más rápido que ag dependiendo de su caso de uso.

Una cosa que he encontrado más rápido para usar grep para buscar (especialmente para cambiar patrones) en un solo archivo grande es usar split + grep + xargs con su bandera paralela. Por ejemplo:

Tener un archivo de identificadores que desea buscar en un archivo grande llamado my_ids.txt Nombre de bigfile bigfile.txt

Use división para dividir el archivo en partes:

 # Use split to split the file into x number of files, consider your big file # size and try to stay under 26 split files to keep the filenames # easy from split (xa[az]), in my example I have 10 million rows in bigfile split -l 1000000 bigfile.txt # Produces output files named xa[at] # Now use split files + xargs to iterate and launch parallel greps with output for id in $(cat my_ids.txt) ; do ls xa* | xargs -n 1 -P 20 grep $id >> matches.txt ; done # Here you can tune your parallel greps with -P, in my case I am being greedy # Also be aware that there's no point in allocating more greps than x files 

En mi caso, esto cortó lo que hubiera sido un trabajo de 17 horas en un trabajo de 1 hora y 20 minutos. Estoy seguro de que hay algún tipo de curva de campana aquí en la eficiencia y, obviamente, revisar los núcleos disponibles no te servirá de nada, pero esta fue una solución mucho mejor que cualquiera de los comentarios anteriores para mis requisitos, como se indicó anteriormente. Esto tiene un beneficio adicional sobre el script paralelo en el uso principalmente de herramientas nativas (linux).

cgrep, si está disponible, puede ser órdenes de magnitud más rápido que grep.

MCE 1.508 incluye una secuencia de comandos {wrappers, listas} de doble nivel que admite muchos binarios de C; agrep, grep, egrep, fgrep y tre-agrep.

https://metacpan.org/source/MARIOROY/MCE-1.509/bin/mce_grep

https://metacpan.org/release/MCE

No es necesario convertir a minúsculas cuando se quiere -i para ejecutar rápido. Simplemente pase –lang = C a mce_grep.

El orden de salida se conserva. La salida -n y -b también es correcta. Desafortunadamente, ese no es el caso del paralelo GNU mencionado en esta página. Realmente estaba esperando que GNU Parallel trabaje aquí. Además, mce_grep no sub-shell (sh -c / path / to / grep) cuando se llama al binario.

Otra alternativa es el módulo MCE :: Grep incluido con MCE.

Una ligera desviación del tema original: las utilidades de la línea de comandos de búsqueda indexada del proyecto googlecodesearch son mucho más rápidas que grep: https://github.com/google/codesearch :

Una vez que lo comstack (se necesita el paquete de golang ), puede indexar una carpeta con:

 # index current folder cindex . 

El índice se creará bajo ~/.csearchindex

Ahora puedes buscar:

 # search folders previously indexed with cindex csearch eggs 

Todavía estoy canalizando los resultados a través de grep para obtener coincidencias coloreadas.