regular pattern online regex sed grep

pattern - sed regex replace



SED y GREP mostrando diferentes resultados (3)

Como se menciona en los comentarios, está buscando un rango de expresiones, y sed hará coincidir todas las líneas desde el primer partido del inicio hasta el primer partido del final. Como lenguaje propio, awk proporciona más flexibilidad que sed :

start=26/Apr/2017:08:00:21 end=26/Apr/2017:08:02:04 awk -v "s=$start" -v "e=$end" ''$0~s{m=1} $0~e{m=0; f=1; print} f&&$0!~e{exit} m'' access.log

Tenemos 4 bloques condicionales. Primero buscamos una coincidencia al inicio y configuramos m . Luego buscamos una coincidencia al final y desarmamos m , establecemos f y continuamos imprimiendo. La siguiente comprobación es para f , siempre que no haya coincidencia en el extremo. Esto indica que hemos terminado todas las coincidencias para la cadena final y podemos salir. El bloque final comprueba si m está configurado e imprime si lo está.

Una versión más detallada del mismo programa:

awk -v "start_date=$start" -v "end_date=$end" '' { if ($0 ~ start_date) { matching = 1; } else if ($0 ~ end_date) { matching = 0; finishing = 1; print $0; } else if (finishing) { exit; } if (matching) { print $0; } } '' access.log

¡Gracias a @alvits por golpearme en la cabeza en los comentarios hasta que descubrí una solución mejor!

Estoy tratando de obtener la cantidad de solicitudes en un rango de tiempo específico de mi registro de Apache. Pensé que era bastante fácil hacerlo con sed pero cuando intenté hacer lo mismo con grep me di cuenta de que grep muestra más resultados que sed .

Aquí está el comando grep que utilicé:

#grep ''26/Apr/2017:08:0[0-2]:[0-2][0-4]'' access.log 10.51.32.104 - - [26/Apr/2017:08:00:21 +0100] "GET / HTTP/1.1" 301 762 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36" 10.51.32.104 - - [26/Apr/2017:08:00:22 +0100] "GET /index.php?action=Login&module=Users HTTP/1.1" 200 6591 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36" 172.30.180.113 - - [26/Apr/2017:08:02:04 +0100] "GET / HTTP/1.0" 301 1906 "-" "Mozilla/4.0 (compatible; ipMonitor 10.7)" 172.30.180.113 - - [26/Apr/2017:08:02:04 +0100] "GET /index.php?action=Login&module=Users HTTP/1.0" 200 21951 "-" "Mozilla/4.0 (compatible; ipMonitor 10.7)"

Y aquí está el comando sed :

#sed -n ''/26//Apr//2017:08:00:21/ , /26//Apr//2017:08:02:04/p'' access.log 10.51.32.104 - - [26/Apr/2017:08:00:21 +0100] "GET / HTTP/1.1" 301 762 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36" 10.51.32.104 - - [26/Apr/2017:08:00:22 +0100] "GET /index.php?action=Login&module=Users HTTP/1.1" 200 6591 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36" 172.30.180.113 - - [26/Apr/2017:08:02:04 +0100] "GET / HTTP/1.0" 301 1906 "-" "Mozilla/4.0 (compatible; ipMonitor 10.7)"

Entonces, como puede ver, falta un acceso de 172.30.180.113 que coincida con el patrón.

¿Qué hice mal? ¿Tendría algún otro parámetro en sed ayudado, o hay una mejor manera de hacer esto?


Estás bastante cerca de resolverlo usando sed . Ese es un buen comienzo y los alentaré a seguir esa ruta.

Por supuesto, puede usar regex pero tiene su limitación. Tenga en cuenta el rango 08:00 a 09:59 , la expresión regular será fácil 0[89]:[0-5][09] . Pero si el rango es de 08:45 a 09:30 , entonces regex no será tu amigo. Por lo tanto, mi aliento para usar el rango como lo intentó.

La limitación que has visto con sed es que se cumple el rango final y sed ha dejado de procesar desde allí. Pero sabemos que habrá más líneas que caen dentro del rango final.

sed -n ''/26//Apr//2017:08:00:21/,/26//Apr//2017:08:02:04/{p;b};/26//Apr//2017:08:02:04/p'' access.log

Descomponiendo los comandos de sed:

/26//Apr//2017:08:00:21/,/26//Apr//2017:08:02:04/{p;b}

Esto mostrará la línea si está dentro del rango y luego b ranchará hasta el final de los comandos de sed .

/26//Apr//2017:08:02:04/p

Esto solo se ejecutará si está fuera del rango en el comando sed anterior. Esto cuidará las líneas adicionales que caen dentro del rango pero sed no las considera dentro del alcance.

La misma técnica se puede usar con awk .

awk ''/26//Apr//2017:08:00:21/,/26//Apr//2017:08:02:04/{a=NR;print};a!=NR && /26//Apr//2017:08:02:04/{print}'' access.log

El primer comando:

/26//Apr//2017:08:00:21/,/26//Apr//2017:08:02:04/{a=NR;print}

Imprimirá las líneas dentro del rango y establecerá la variable a al valor de NR (número de registro actual).

El segundo comando:

a!=NR && /26//Apr//2017:08:02:04/{print}

Se imprimirán las líneas restantes que están dentro del rango pero awk considerado fuera del rango.


Sí, hay una mejor manera de hacer esto (que menciono en la parte inferior). Dado que las recomendaciones estarían fuera del tema de , responderé con una explicación sobre lo que sucede dentro del código que ha proporcionado.

Su comando grep imprime cada línea de entrada que coincide con la expresión regular que ha especificado. Mientras esto funciona, a veces es difícil especificar rangos puramente en expresiones regulares. (¿Cómo especificarías un rango del 10 de enero al 2 de marzo?)

Un comando sed puede ser un poco más complejo. Considera lo siguiente:

$ sed -n -e ''/re/p''

Esto imprimirá todas las líneas que coincidan con la expresión regular re . Básicamente lo mismo que grep .

$ sed -n -e ''/re1/,/re2/p''

Esto imprimirá todas las líneas comenzando con la primera coincidencia de re1 y terminando con la primera coincidencia de re2 . Esto es lo que está haciendo el script sed en su pregunta. Tenga en cuenta que esto también tiene el potencial de imprimir líneas que NO coinciden con una de las expresiones regulares:

$ printf ''one/ntwo/nthree/nfour/n'' | sed -ne ''/one/,/three/p'' one two three

Si desea extraer recuentos de líneas en sus registros utilizando sed, recomiendo un enfoque alternativo. Si bien sed es excelente para la coincidencia de patrones, no proporciona herramientas que puedan interpretar las fechas. Perl, o gawk, o incluso bash proporcionarían más funcionalidad, y serían más fáciles de comprender / depurar dentro de seis meses cuando necesites hacer cambios en tu código.