Grep multicolore

30

J'essaie d'obtenir chaque commande grep pour mettre en évidence ses résultats dans une couleur différente. Je peux le faire manuellement avec une ligne comme celle-ci:

ls -l GREP_COLORS='mt=01;32' grep c | GREP_COLORS='mt=01;31' grep o | GREP_COLORS='mt=01;34' grep n | GREP_COLORS='mt=01;36' grep f

Chaque cpersonnage sera surligné en vert et chaque opersonnage sera surligné en rouge, etc ...

Pour que cet exemple fonctionne, vous devez vous assurer que vous disposez toujours --color=alwaysde vos commandes grep. J'ai mis cela dans mon .bashrc afin que grep ait toujours des couleurs:

export GREP_OPTIONS='--color=always'


Ce que j'essaie d'accomplir, c'est d'envelopper cette fonctionnalité avec un alias afin que je puisse simplement appeler grepet avoir une GREP_COLORSvaleur différente à chaque fois. Je comprends la prise en compte de plusieurs shells pour chaque nouveau grep canalisé et j'essaie de surmonter cela en créant des fichiers (un pour chaque couleur), pour indiquer qu'ils ont déjà été utilisés.

J'ai fait quelques tentatives mais étrangement, celle-ci semble fonctionner "au mieux". J'ai ceci dans mon .bashrc:

alias mg="mygrep"
mygrep(){
    # define possible colors
    COLORS=("01;32" "01;31" "01;34" "01;36")
    COUNTER=0
    NUM=0
    # as long as the color has already been used, keep searching
    while [ -f /home/lior/Desktop/mygrep_$NUM ]; do
        # get a random index
        let NUM=`shuf --input-range=0-$(( ${#COLORS[*]} - 1 )) | head -1`
        wait ${!}
        $(( COUNTER+=1 ))
        if [ "$COUNTER" -ge ${#COLORS[@]} ]; then
            # remove all color locks
            rm /home/lior/Desktop/mygrep_*
            wait ${!}
        fi
    done
    # mark this color as used
    touch /home/lior/Desktop/mygrep_$NUM
    wait ${!}

    # lets go!
    GREP_COLORS="mt=${COLORS[$NUM]}" grep "$@"
}

J'utilise cet alias comme ceci:

ll | mg c | mg o | mg n | mg f

Les résultats sont assez sympas. Il y a cependant des erreurs légèrement différentes à chaque fois. Voici quelques captures d'écran:

Il semble que lorsque le shell passe par chaque commande de canal, la fonction précédente n'a pas encore terminé son exécution. Il essaie de supprimer les fichiers qui n'existent plus. Je ne sais pas trop d'où command not foundviennent ces autres erreurs.

Comme vous pouvez le voir, j'ai mis quelques waitcommandes pour essayer de terminer la manipulation du fichier mais cela ne semble pas fonctionner trop bien. Une autre chose que j'ai déjà essayée est d'utiliser la mémoire partagée /dev/shmmais elle a donné des résultats similaires.

Comment pourrais-je obtenir les résultats souhaités?

Remarque:

Je cherche des réponses qui enveloppent simplement la commande grep car elle a beaucoup de fonctionnalités que je veux utiliser et j'ai l'intention d'insérer une autre logique entre les canaux, donc je ne veux pas fournir tous les termes de recherche à la fois. Je ne suis pas non plus à la recherche d'autres outils "grep like". Désolé à @terdon qui a déjà posté une super suggestion de Perl.

Lix
la source
Votre premier exemple ne correspond pas à ce que vous expliquez dans la partie restante, juste en disant.
Bernhard
@bernhard Je ne comprends pas ce que vous voulez dire. Mon intention est d'utiliser mon alias dans le cadre d'une commande plus large utilisant des tuyaux ... Veuillez me faire savoir de quelle contradiction vous parlez ...
Lix
Je pensais que tu voulais aussi utiliser ton pseudonyme en dehors des tuyaux. Quoi qu'il en soit, votre premier exemple ne fonctionne pas pour moi. Avez-vous essayé alias mg="mygrep; grep"?
Bernhard
@Bernhard - Je travaille sur une boîte Ubuntu 12.04. Je ne serais pas surpris s'il y avait de légères différences ... J'ai essayé votre suggestion, le problème est que cela mygrep;se transforme en une nouvelle commande en soi et que le flux de données est perdu. Le tuyau entrant de la lsserait transmis à mygrep;et non à grep. C'est du moins ainsi que je le comprends.
Lix
@Bernhard - Ah .. Je pense que je sais pourquoi cela n'a pas fonctionné pour vous. Vous devez vous assurer que vous disposez --color=alwaysde toutes vos commandes grep. J'ai mis cela globalement dans mon .bashrc. J'ai édité ça dans le post.
Lix

Réponses:

6

Voici une approche différente. J'ai un petit script Perl que j'ai déjà publié dans une autre réponse qui mettra en évidence les motifs fournis par l'utilisateur dans différentes couleurs. Une version légèrement modifiée du script agira comme grep:

#!/usr/bin/env perl
use Getopt::Std;
use strict;
use Term::ANSIColor; 

my %opts;
getopts('hic:l:',\%opts);
    if ($opts{h}){
      print<<EoF; 
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

EoF
      exit(0);
    }

my $case_sensitive=$opts{i}||undef;
my @color=('bold red','bold blue', 'bold yellow', 'bold green', 
       'bold magenta', 'bold cyan', 'yellow on_blue', 
       'bright_white on_yellow', 'bright_yellow on_red', 'white on_black');
if ($opts{c}) {
   @color=split(/,/,$opts{c});
}
my @patterns;
if($opts{l}){
     @patterns=split(/,/,$opts{l});
}
else{
    $patterns[0]='\*';
}

# Setting $| to non-zero forces a flush right away and after 
# every write or print on the currently selected output channel. 
$|=1;

while (my $line=<>) 
{ 
    my $want=0;
    for (my $c=0; $c<=$#patterns; $c++){
    if($case_sensitive){
        if($line=~/$patterns[$c]/){
           $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ge;
           $want++;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
          $want++;
        }
      }
    }
print STDOUT $line if $want>0;
}

Si vous enregistrez ce script cgrepquelque part dans votre PATHet le rendez exécutable, vous pouvez spécifier jusqu'à 10 modèles différents, chacun étant imprimé dans une couleur différente:

entrez la description de l'image ici

$ cgrep -h
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;
terdon
la source
5

Chaque invocation de grepdans un tube s'exécute dans un shell séparé, vous devrez donc passer un état entre eux. La solution suivante est une façon grossière de gérer cela avec un fichier qui conserve l'index de couleur et un fichier de verrouillage qui garantit que les appels simultanés ne lisent pas la même valeur:

#!/usr/bin/env bash
color_index_file=~/.gitcolor
color_index_lock_file=/tmp/$(basename $0)

colors=()
for index in {31..34}
do
    colors+=("01;$index")
done

until mkdir "$color_index_lock_file" 2>/dev/null
do
    :
done

color_index=$(($(cat "$color_index_file" || echo 0) + 1))

if [[ $color_index -ge ${#colors[@]} ]]
then
    color_index=0
fi

printf "$color_index" > "$color_index_file"
rmdir "$color_index_lock_file"

GREP_COLORS="mt=01;${colors[$color_index]}" grep --color=always "$@"

Testez en supposant que vous avez nommé votre copie cgrepet placez-la sur votre PATH:

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz
l0b0
la source
Les seules variables qui doivent vraiment être conservées sont COLOR_INDEXet GREP_COLORS. J'ai essayé d'exporter ces derniers à la fin de la fonction sans succès. C'est ce que vous vouliez dire? Tout simplement pour l'avoir export VAR, non?
Lix
Oh - et oui .. faute de frappe là-bas avec COLOR_TOGGLE. Merci de l'avoir attrapé :)
Lix
1
@ l0b0 L'exportation ne fonctionne pas non plus pour moi, il faut pour l'instant revenir en arrière jusqu'à ce qu'elle réponde vraiment à la question.
Bernhard
@Bernhard Est-ce que cela fonctionne pour vous?
l0b0
Merci pour votre contribution! J'ai incorporé votre grep "$@"suggestion - qui a trié l'alias pour exécuter la fonction, puis grep.
Lix
1

Si vous êtes bon avec les expressions régulières, vous voudrez peut-être consulter grc et grcat. grc appelle grcat.

grcat utilise des fichiers de configuration où vous pouvez ajouter des expressions régulières pour faire correspondre le texte à afficher dans chaque couleur. Il a également un certain nombre d'autres options. Par défaut, il colorise les fichiers journaux du système.

Selon ce que vous avez en tête pour votre script final, vous pourrez peut-être coloriser votre sortie avec une seule commande.

L'astuce consiste à spécifier correctement les expressions rationnelles pour chaque "champ" de votre source de données. Ce sera beaucoup plus facile si vos données ont une structure relativement uniforme.

La dernière fois que je l'ai essayé, je ne suis pas allé trop loin, mais je vais peut-être recommencer parce que je suis un peu mieux en regex que je ne l'étais alors.

Il existe également la commande tput qui peut être utilisée pour envoyer des informations (comme les changements de couleur) directement à votre terminal.

Les deux approches sont couvertes par l'article ci-dessous. Il parle de la commande find, mais il peut être appliqué à la sortie de n'importe quelle commande.

Sortie FIND colorée?

Joe
la source