Redirección de salida dependiendo de grep regex

8

Estoy usando gradle runpara iniciar un servidor REST. La salida del servidor REST se ve así:

XXX.XXX.XX.XXX - <moreinfo>
randomtext
randomtext
XXX.XXX.XX.XXX - <moreinfo>
XXX.XXX.XX.XXX - <moreinfo>
randomtext
XXX.XXX.XX.XXX - <moreinfo>

XXX.XXX.XX.XXXAquí hay una dirección IP, el texto aleatorio son mensajes de error. Toda la salida se dirige a stdout, lamentablemente.

¿Cómo puedo dirigir todas las líneas que comienzan con una dirección IP a un archivo llamado err.logy todas las demás líneas all.log?

Desafortunadamente, gradle runsolo se puede iniciar una vez y no se detiene, ya que es un servidor REST.

Tal vez utilizar una tee, grepcombinación?

polimero
fuente

Respuestas:

8

En Bash, puede usar la sustitución de procesos con tee:

tee >(grep XXX > err.log) | grep -v XXX > all.log

Esto colocará todas las líneas que coincidan con XXX err.logy todas las líneas all.log. >( ... )crea el proceso entre paréntesis y conecta su salida estándar a una tubería. Esto funciona en zsh y otras conchas modernas también.

También puede usar el peecomando de moreutils :

pee "grep XXX > err.log" "grep -v XXX > all.log"

pee redirige la entrada estándar a múltiples comandos ("tee para tuberías").

Otra alternativa es con awk:

awk '{ if (/^([0-9]{1,3}\.){3}[0-9]{1,3}/) { print > "err.log" } else { print > "all.log" } }'

Eso solo prueba cada línea contra la expresión y escribe todo en err.logsi coincide o all.logno.

La expresión regular awk también es adecuada grep -E(aunque coincide con algunas direcciones incorrectas, 999.0.0.0etc., pero eso probablemente no sea un problema).

Michael Homer
fuente
Hmm err.logestá vacío y toda la salida se redirige al all.loguso del teecomando anterior.
polym
Verifique que su expresión regular realmente coincida con las líneas correctas; si err.logexiste, el comando se ejecutó pero no salió nada. grep -Econ la expresión utilizada en el comando awk debería coincidir, o lo hace aquí.
Michael Homer
Ah ok lo tengo ¿Puedes modificar tu pregunta para que all.logno contenga las líneas coincidentes en la expresión grep?
polym
Hecho, no estaba seguro de cuál querías, así que tuve ambas.
Michael Homer
Oh, lo siento, funcionó. Sobreescribí all.logy err.logcon un viejo comando. Perdón por la confusion. Gracias, eres increíble :)) !!
polym
4

Por lo tanto, parece que gradle runno cumpla con tee, pee, grepy io-redirección. Siempre deja de leer después de 4096 bytes.

Para evitar este problema, readcada línea de gradle run. Todavía no lo probé, pero supongo que la lectura de una línea de más de 4k caracteres también fallará.

De todos modos, aquí está el código para resolver mi pregunta específicamente:

#!/bin/bash
STDOUTLOG="/log/stdout.txt"
STDERRLOG="/log/stderr.txt"
while read -r line; do
    [[ $line =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.* ]] && printf '%s\n' "$line" >> "$STDERRLOG" && continue
    printf '%s\n' "$line" >> "$STDOUTLOG"
done < <(gradle run)
polimero
fuente
1
Debe utilizar read -r liney printf '%s\n' "$line"para evitar algunos bordes casos rompiendo cosas.
nyuszika7h
@ nyuszika7h ¡Gracias! Modifiqué la respuesta en consecuencia :).
polym