He ejecutado los siguientes dos comandos para archivos muy grandes.
grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4
awk '/string1|string2/ && /string3/ && /string4/' 151103*.log
La ejecución tardó casi el mismo tiempo. Pero awk
fue mucho más rápido mostrarme los resultados que coincidían. grep
También me mostró el mismo resultado pero al final, cuando se completó el proceso.
Ambos tardaron el mismo tiempo en completarse el proceso, solo quiero saber la lógica detrás de las búsquedas de awk
y grep
.
¿Por qué es awk
más rápido? ¿Ambos programas tienen una lógica de búsqueda diferente? ¿Qué pasa si confundo las cadenas en la búsqueda anterior? ¿Hay alguna diferencia en la velocidad de búsqueda?
Respuesta1
GNU grep
almacena en buffer la salida, pero GNU awk
no. E incluso si no estuviera usando GNU awk
y estuviera usando alguna otra variante, probablemente aún tendría un búfer de línea si estuviera imprimiendo en una terminal y, por lo tanto, eliminaría la salida para cada \n
línea ew que ocurra, pero sus grep
escrituras en una tubería y, por lo tanto, bloquearían. buffer de todos modos. Si tienes un GNU grep
puedes usarlo grep --line-buffered ... | grep ...
para comparar y ver los resultados lo más rápido posible. Probablemente grep
superará awk
prácticamente cualquier prueba de coincidencia, especialmente un GNU grep
.
Aquí sed
también puedes hacer lo que quieras:
sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out
Respuesta2
La canalización grep no pudo generar nada hasta que el final grep
de string4 coincidiera con algo, y solo obtiene su entrada después de que se llena el búfer de canalización anterior. Ver preguntas relacionadas¿Qué tamaño tiene el amortiguador de tubería?yDesactivar el almacenamiento en búfer en la tubería.
Dependiendo de la frecuencia de las cadenas en su entrada, podría ver una diferencia en los tiempos de ejecución al colocar las búsquedas estáticas primero, para que las expresiones regulares extendidas tengan menos que mirar.
Respuesta3
Su ejemplo de awk consiste en realizar toda la búsqueda de expresiones regulares de una sola vez. Para cada línea de entrada, si se encuentra la primera, segunda y tercera expresión regular, la línea se imprimirá y verá el resultado esencialmente de inmediato (al procesar la línea coincidente).
Su ejemplo de grep utiliza 3 invocaciones diferentes de grep (una para cada expresión regular) para hacer lo mismo, pero la salida de cada invocación se convierte en la entrada para la siguiente, lo que significa que cada una debe completarse antes de que la siguiente tenga algo que procesar.
Si tuviera un solo archivo de 1000 líneas y solo la línea 5 coincidiera con las tres expresiones regulares, el comando awk le daría resultados después de procesar la quinta línea, antes de procesar la sexta línea. Compare eso con las declaraciones grep canalizadas. La primera invocación de grep encontraría la quinta línea y cualquier otra línea que pueda coincidir con la primera expresión regular, y después de procesar la línea número 1000 (final) de entrada, su salida se convierte en la entrada para la segunda invocación de grep. La segunda invocación de grep procesa tantas líneas como sea posible de la primera salida y genera las líneas que coinciden con la primera y la segunda expresión regular, que luego se convierte en la entrada para la tercera invocación de grep. A medida que la tercera invocación de grep procesa cada línea, generará cualquier línea que coincida con su expresión regular.
Puede comparar los mejores y peores casos de grep para el ejemplo anterior: si ninguna de las líneas coincide con ninguna expresión regular excepto la línea 5, que coincide con las 5, entonces el primer grep procesa 1000 líneas, el segundo grep procesa 1 línea y el tercer grep procesa 1 línea: procesará 1002 líneas antes de tener algún resultado (en el mejor de los casos). Si todas las líneas coinciden con las dos primeras expresiones regulares pero solo una línea coincide con la tercera expresión regular, entonces la construcción del grep canalizado procesará 1000 + 1000 líneas + 5 = 2005 líneas antes de encontrar la coincidencia en la quinta línea y tener algún resultado (lo hará continúe procesando las 995 líneas restantes de la salida del segundo grep, pero no verá más resultados porque nada más coincidirá).
Compare eso con el comando awk, que verifica las tres expresiones regulares simultáneamente para cada línea y le brinda resultados después de procesar la quinta línea. La diferencia será exagerada a medida que revise más archivos simultáneamente.
Por ejemplo, compare si ve un resultado más rápido si en lugar de ejecutar el comando grep en todos los archivos simultáneamente como lo hizo anteriormente (en teoría, debería hacerlo, pero los resultados pueden variar dependiendo de la distribución de accesos en sus archivos):
grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4
en su lugar, ejecuta la serie de comandos grep en cada archivo individualmente, así:
for i in 151103*.log;
do grep -E 'string1|string2' $i |grep 'string3' | grep string4;
done
Esto aún no producirá resultados tan rápido como la declaración awk, pero es posible que vea una diferencia.
Respuesta4
Si bien grep, awk y sed se pueden usar para tareas similares, cada uno tiene sus fortalezas y debilidades.
Awk funciona mejor para datos tabularizados o cuando necesita realizar cálculos, etc.
Sed destaca en la sustitución de texto.
Lo mejor es que grep seleccione filas de los datos de entrada, por lo que esperaba que fuera más rápido que awk para esta tarea. Quizás si combinas los 3 comandos grep en uno, eso es lo que verás. En este momento, grep está en desventaja ya que necesita iniciarse 3 veces y la segunda y la tercera deben esperar la entrada de la primera. Lo que podría explicar por qué el resultado llega con retraso. Aunque no estoy seguro de eso.