Filtrer la sortie de la commande par couleur

13

J'utilise un utilitaire qui n'offre pas de moyen de filtrer sa sortie. Rien dans le texte de la sortie n'indique qu'une fonction particulière a échoué mais elle apparaît en rouge. La sortie est si longue qu'à la fin, quand elle signale un certain nombre d'erreurs, je ne peux pas toujours faire défiler pour voir la sortie où l'erreur s'est produite.

Comment filtrer le texte non rouge?

pseudo code:

dolongtask | grep -color red

Éditer

La commande émet d' autres couleurs aussi bien et je dois être en mesure de filtrer sur tout le texte qui n'est pas rouge. La coloration du texte est également multiligne.

km6zla
la source
1
Je m'excuse de demander l'évidence - mais toutes les sorties sont activées >&1? Je veux dire, les trucs rouges ne disparaissent pas si vous 2>/dev/null, non?
mikeserv

Réponses:

15

Le changement de couleur se fait via des séquences d'échappement intégrées dans le texte. Invariablement, les programmes émettent des séquences d'échappement ANSI , car c'est ce que pratiquement tous les terminaux prennent en charge de nos jours.

La séquence d'échappement pour passer la couleur de premier plan au rouge est \e[31m, où \edésigne un caractère d'échappement (octal 033, hexadécimal 1b, également connu sous le nom ESC, ^[et diverses autres désignations). Les nombres compris entre 30 et 39 définissent la couleur de premier plan; d'autres nombres définissent des attributs différents. \e[0mréinitialise tous les attributs à leur valeur par défaut. Exécutez cat -vpour vérifier ce que le programme imprime, il peut utiliser une variante telle que \e[0;31mréinitialiser d'abord tous les attributs, ou \e[3;31également activer l'italique (que de nombreux terminaux ne prennent pas en charge).

Dans ksh, bash ou zsh, vous pouvez utiliser $'…'pour activer les échappements antislash à l'intérieur des guillemets, ce qui vous permet de taper $'\e'pour obtenir un caractère d'échappement. Notez que vous devrez ensuite doubler toute barre oblique inverse à laquelle vous souhaitez passer grep. Dans /bin/sh, vous pouvez utiliser "$(printf \\e)"ou saisir un caractère d'échappement littéral.

Avec l' grep -ooption GNU , l'extrait de code suivant filtre le texte rouge, en supposant qu'il commence par la séquence d'échappement \e[31m, se termine par l'une \e[0mou \e[30mla même ligne et ne contient aucune séquence d'échappement intégrée.

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

L' awkextrait de code suivant extrait du texte rouge, même lorsqu'il est multiligne.

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'

Voici une variante qui conserve les commandes de changement de couleur, ce qui pourrait être utile si vous filtrez plusieurs couleurs (ici le rouge et le 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- arrête d'être méchant'
la source
La solution awk a fonctionné pour moi. Est-il possible de conserver les couleurs en sortie?
km6zla
@ ogc-nick Vous voulez une sortie tout en rouge? printf '\e[31m'; awk …; printf '\e[0m'
Gilles 'SO- arrête d'être méchant'
Juste pour la couleur que je filtre pour être conservée dans la sortie.
km6zla
@ ogc-nick Voir ma modification.
Gilles 'SO- arrête d'être méchant'
6

Vous pouvez demander à grep de rechercher des caractères de contrôle, dont certains sont responsables de la création des jolies couleurs sur le terminal.

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

Par exemple, cela fait écho à un "test" rouge dans grep, qui le trouve car il est entouré de caractères de contrôle:

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

Il --color=nones'agit simplement de s'assurer que grep n'applique pas sa propre colorisation à la sortie correspondante, mais imprime fidèlement la ligne entière afin que les caractères de contrôle soient interprétés par le shell.

savanto
la source
Agréable. Je me demande si on pourrait aller plus loin et faire quelque chose comme grep -E $'\033\[0?[01];31m.+?\033\[0?0m'ou grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'tester spécifiquement le rouge?
steeldriver
J'ai commencé à trouver des expressions rationnelles comme celles que vous suggérez, mais avant de pouvoir les faire fonctionner, je suis tombé sur [[:cntrl:]]. J'ai testé le vôtre et ils fonctionnent pour moi, c'est à dire. correspondant au rouge et ne correspondant pas aux autres couleurs.
savanto
Fonctionne très bien mais correspondra à n'importe quelle couleur. Je ne l'ai pas mentionné dans la question mais de nombreuses autres couleurs sont également sorties et je veux juste voir les trucs rouges. +1 pour un code simple et fonctionnel.
km6zla