Filtra l'output del comando per colore


13

Sto eseguendo un'utilità che non offre un modo per filtrare il suo output. Nulla nel testo dell'output indica che una particolare funzione non è riuscita ma viene visualizzata in rosso. L'output è così lungo che alla fine quando riporta alcuni # errori non riesco sempre a scorrere per vedere l'output in cui si è verificato l'errore.

Come posso filtrare il testo non rosso?

pseudo codice:

dolongtask | grep -color red

modificare

Il comando emette altri colori come bene e ho bisogno di essere in grado di filtrare fuori tutto il testo che non è rosso. Anche la colorazione del testo è multilinea.


1
Mi scuso per aver chiesto l'ovvio, ma tutto l'output è attivo >&1? Voglio dire, le cose rosse non vanno via se tu 2>/dev/null, giusto?
Mikeserv,

Risposte:


15

Il cambio del colore avviene tramite sequenze di escape incorporate nel testo. Invariabilmente, i programmi emettono sequenze di escape ANSI , perché questo è ciò che praticamente supporta tutti i terminali al giorno d'oggi.

La sequenza di escape per cambiare il colore di primo piano in rosso è \e[31m, dove \edesigna un carattere di escape (033 ottale, 1b esadecimale, noto anche come ESC ^[e varie altre designazioni). I numeri nell'intervallo 30–39 impostano il colore di primo piano; altri numeri impostano attributi diversi. \e[0mripristina tutti gli attributi al loro valore predefinito. Esegui cat -vper verificare ciò che il programma stampa, potrebbe utilizzare alcune varianti come \e[0;31mripristinare prima tutti gli attributi o \e[3;31anche attivare il corsivo (che molti terminali non supportano).

In ksh, bash o zsh, è possibile utilizzare $'…'per abilitare le escape di barra rovesciata all'interno delle virgolette, che consente di digitare $'\e'per ottenere un carattere di escape. Nota che dovrai quindi raddoppiare qualsiasi barra rovesciata a cui vuoi passare grep. In /bin/sh, puoi usare "$(printf \\e)"o digitare un carattere di escape letterale.

Con l' grep -oopzione GNU , il seguente frammento filtra il testo rosso, supponendo che inizi con la sequenza di escape \e[31m, termina con una \e[0mo \e[30msulla stessa riga e non contenga alcuna sequenza di escape incorporata.

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

Il awkframmento seguente estrae il testo rosso, anche quando è multilinea.

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'

Ecco una variante che conserva i comandi di cambio colore, che potrebbe essere utile se stai filtrando più colori (qui rosso e 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'

La soluzione awk ha funzionato per me. Un modo per conservare il colore in uscita?
km6zla

@ ogc-nick Vuoi un output tutto rosso? printf '\e[31m'; awk …; printf '\e[0m'
Gilles 'SO- smetti di essere malvagio' il

Solo per qualsiasi colore sto filtrando per essere mantenuto nell'output.
km6zla

@ ogc-nick Vedi la mia modifica.
Gilles 'SO- smetti di essere malvagio' il

6

Puoi avere grep alla ricerca di personaggi di controllo, alcuni dei quali sono responsabili della creazione dei bei colori sul terminale.

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

Ad esempio, questo fa eco a un "test" rosso in grep, che lo trova dovuto al fatto che è circondato da caratteri di controllo:

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

Lo scopo --color=noneè solo di assicurarsi che grep non applichi la propria colorazione all'output abbinato, ma stampa fedelmente l'intera linea in modo che i caratteri di controllo vengano interpretati dalla shell.


Bello. Mi chiedo se si potrebbe andare oltre e fare qualcosa di simile grep -E $'\033\[0?[01];31m.+?\033\[0?0m'o grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'testare specificamente il rosso?
Steeldriver,

Ho iniziato a trovare regex come quelle che suggerisci, ma prima che potessi farle funzionare mi sono imbattuto in [[:cntrl:]]. Ho testato il tuo e loro lavorano per me, vale a dire. corrispondenza del rosso e mancata corrispondenza con altri colori.
Savanto,

Funziona alla grande ma si adatta a qualsiasi colore. Non l'ho menzionato nella domanda, ma molti altri colori vengono emessi e voglio solo vedere le cose rosse. +1 per codice semplice e funzionante.
km6zla
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.