Filtrar salida de comando por color

13

Estoy ejecutando una utilidad que no ofrece una forma de filtrar su salida. Nada en el texto de la salida indica que una función en particular falló pero se muestra en rojo. El resultado es tan largo que al final, cuando informa algunos # de errores, no siempre puedo desplazarme para ver el resultado donde ocurrió el error.

¿Cómo puedo filtrar el texto no rojo?

pseudocódigo:

dolongtask | grep -color red

Editar

El comando de salida a otros colores también y tengo que ser capaz de filtrar a cabo todo el texto que no es rojo. También el color del texto es multilínea.

km6zla
fuente
1
Pido disculpas por preguntar lo obvio, pero ¿todos los resultados están activados >&1? Quiero decir, las cosas rojas no desaparecen si tú 2>/dev/null, ¿verdad?
mikeserv

Respuestas:

15

El cambio de color se realiza mediante secuencias de escape incrustadas en el texto. Invariablemente, los programas emiten secuencias de escape ANSI , porque eso es lo que prácticamente todos los terminales soportan hoy en día.

La secuencia de escape para cambiar el color de primer plano a rojo es \e[31m, donde \edesigna un carácter de escape (octal 033, hexadecimal 1b, también conocido como ESC, ^[y varias otras designaciones). Los números en el rango 30–39 establecen el color de primer plano; otros números establecen diferentes atributos. \e[0mrestablece todos los atributos a su valor predeterminado. Ejecute cat -vpara verificar lo que imprime el programa, podría usar alguna variante, como \e[0;31mrestablecer primero todos los atributos, o \e[3;31también activar la cursiva (que muchos terminales no admiten).

En ksh, bash o zsh, puede usar $'…'para habilitar los escapes de barra invertida dentro de las comillas, lo que le permite escribir $'\e'para obtener un carácter de escape. Tenga en cuenta que tendrá que duplicar cualquier barra invertida a la que desee pasar grep. En /bin/sh, puede usar "$(printf \\e)"o escribir un carácter de escape literal.

Con la grep -oopción GNU , el siguiente fragmento filtra el texto rojo, suponiendo que comienza con la secuencia de escape \e[31m, termina con una \e[0mo \e[30men la misma línea y no contiene ninguna secuencia de escape incrustada.

grep -Eo $'\e\\[31m[^\e]*\e\\[[03]?m'

El siguiente awkfragmento extrae el texto rojo, incluso cuando es multilínea.

awk -v RS='\033' '
    match($0, /^\[[0-9;]*m/) {
        color = ";" substr($0, 2, RLENGTH-2) ";";
        $0 = substr($0, RLENGTH+1);
        gsub(/(^|;)0*[^03;][0-9]*($|;)/, ";", color);
        red = (color ~ /1;*$/)
    }
    red'

Aquí hay una variación que conserva los comandos de cambio de color, que podrían ser útiles si está filtrando varios colores (aquí rojo y magenta).

awk -v RS='\033' '
    match($0, /^\[[0-9;]*m/) {
        color = ";" substr($0, 2, RLENGTH-2) ";";
        printf "\033%s", substr($0, 1, RLENGTH);
        $0 = substr($0, RLENGTH+1);
        gsub(/(^|;)0*[^03;][0-9]*($|;)/, ";", color);
        desired = (color ~ /[15];*$/)
    }
    desired'
Gilles 'SO- deja de ser malvado'
fuente
La solución awk funcionó para mí. ¿Alguna forma de retener el color en la salida?
km6zla
@ ogc-nick ¿Desea una salida completamente roja? printf '\e[31m'; awk …; printf '\e[0m'
Gilles 'SO- deja de ser malvado'
Solo para cualquier color que esté filtrando para retenerlo en la salida.
km6zla
@ ogc-nick Ver mi edición.
Gilles 'SO- deja de ser malvado'
6

Puede hacer que grep busque caracteres de control, algunos de los cuales son responsables de crear los bonitos colores en el terminal.

dolongtask | grep '[[:cntrl:]]'

Por ejemplo, esto hace eco de una "prueba" roja en grep, que lo encuentra debido a que está rodeado de caracteres de control:

$ echo -e '\033[00;31mtest\033[00m' | grep --color=none '[[:cntrl:]]'
test     <-- in red

Esto --color=nonees solo para asegurarse de que grep no aplique su propia coloración a la salida coincidente, sino que imprima toda la línea fielmente para que el shell interprete los caracteres de control.

savanto
fuente
Agradable. Me pregunto si uno podría ir más allá y hacer algo como grep -E $'\033\[0?[01];31m.+?\033\[0?0m'o grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'para probar el rojo específicamente.
steeldriver
Empecé a crear expresiones regulares como las que sugieres, pero antes de que pudiera hacer que funcionaran me topé [[:cntrl:]]. Probé el tuyo y funcionan para mí, es decir. a juego con rojo y no coincidiendo con otros colores.
savanto
Funciona muy bien pero coincidirá con cualquier color. No lo mencioné en la pregunta, pero también se muestran muchos otros colores y solo quiero ver el material rojo. +1 para código simple y funcional.
km6zla