Filtrar a saída do comando por cor

13

Estou executando um utilitário que não oferece uma maneira de filtrar sua saída. Nada no texto da saída indica que uma função específica falhou, mas aparece em vermelho. A saída é tão longa que, no final, quando informa um número de erros, nem sempre posso rolar para ver a saída em que ocorreu o erro.

Como filtrar texto não vermelho?

pseudo-código:

dolongtask | grep -color red

Editar

O comando emite outras cores também e eu preciso ser capaz de filtrar para fora todo o texto que não é vermelho. Além disso, a coloração do texto é multilinha.

km6zla
fonte
1
Peço desculpas por perguntar o óbvio - mas toda a saída está ativada >&1? Quero dizer, o material vermelho não desaparece se você 2>/dev/null, certo?
mikeserv

Respostas:

15

A mudança de cor é feita por meio de seqüências de escape incorporadas no texto. Invariavelmente, os programas emitem seqüências de escape ANSI , porque é isso que praticamente todos os terminais suportam atualmente.

A sequência de escape para mudar a cor do primeiro plano para vermelho é \e[31m, onde \edesigna um caractere de escape (octal 033, hexadecimal 1b, também conhecido como ESC ^[e várias outras designações). Os números no intervalo de 30 a 39 definem a cor do primeiro plano; outros números definem atributos diferentes. \e[0mredefine todos os atributos para seu valor padrão. Execute cat -vpara verificar o que o programa imprime, ele pode usar alguma variante, como \e[0;31mprimeiro redefinir todos os atributos ou \e[3;31também ativar o itálico (que muitos terminais não suportam).

No ksh, bash ou zsh, você pode usar $'…'para ativar escapes de barra invertida dentro das aspas, o que permite digitar$'\e' para obter um caractere de escape. Observe que você precisará dobrar qualquer barra invertida para a qual deseja passar grep. Em /bin/sh, você pode usar "$(printf \\e)"ou digitar um caractere de escape literal.

Com a grep -oopção GNU , o seguinte trecho filtra o texto em vermelho, supondo que ele comece com a sequência de escape \e[31m, termine com\e[0m ou \e[30mna mesma linha e não contém nenhuma sequência de escape incorporada.

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

Os seguintes awk fragmento a extrai o texto em vermelho, mesmo quando é multilinha.

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'

Aqui está uma variação que mantém os comandos de mudança de cor, que podem ser úteis se você estiver filtrando várias cores (aqui vermelho 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'
Gilles 'SO- parar de ser mau'
fonte
A solução awk funcionou para mim. Alguma maneira de manter a cor na saída?
precisa
@ ogc-nick Você quer uma saída totalmente vermelha? printf '\e[31m'; awk …; printf '\e[0m'
Gilles 'SO- stop be evil'
Apenas para qualquer cor que eu estou filtrando, para ser retida na saída.
precisa
@ ogc-nick Veja minha edição.
Gilles 'SO- stop be evil'
6

Você pode fazer com que o grep procure caracteres de controle, alguns dos quais são responsáveis ​​por criar as cores bonitas no terminal.

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

Por exemplo, isso ecoa um "teste" vermelho no grep, que o encontra devido a estar cercado por caracteres de controle:

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

A --color=noneé apenas para se certificar grep não se aplica a sua própria colorização à saída combinado, mas imprime toda a linha fielmente para que os caracteres de controle serão interpretados pelo shell.

savanto
fonte
Agradável. Gostaria de saber se alguém poderia ir mais longe e fazer algo como grep -E $'\033\[0?[01];31m.+?\033\[0?0m'ou grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'testar especificamente o vermelho?
steeldriver
Comecei a criar expressões como as que você sugere, mas antes que eu pudesse fazê-las funcionar, me deparei com elas [[:cntrl:]]. Eu testei o seu e eles trabalham para mim, ou seja. combinando vermelho e não combinando com outras cores.
savanto
Funciona muito bem, mas combina com qualquer cor. Eu não mencionei isso na pergunta, mas muitas outras cores também são exibidas e eu só quero ver o material vermelho. +1 para código simples e funcional.
precisa