bash - two - Grep lo más rápido posible
grep not match (12)
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 compilarlo 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?
Al parecer, usar --mmap puede ayudar en algunos sistemas:
http://lists.freebsd.org/pipermail/freebsd-current/2010-August/019310.html
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.
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.
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 GNUparallel
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
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.
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
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.
Si tienes un archivo muy grande:
parallel -j100% --pipepart --block 100M -a <very large SEEKABLE file> grep <...>
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.
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ó http://lists.freebsd.org/pipermail/freebsd-current/2010-August/019310.html 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).
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[a-z]), in my example I have 10 million rows in bigfile
split -l 1000000 bigfile.txt
# Produces output files named xa[a-t]
# 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).
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 compila (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.
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.
cgrep, si está disponible, puede ser órdenes de magnitud más rápido que grep.