Grep multicolore


30

Sto cercando di ottenere ogni comando grep per evidenziare i risultati in un colore diverso. Posso farlo manualmente con una linea come questa:

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

Ogni cpersonaggio verrà evidenziato in verde e ogni opersonaggio verrà evidenziato in rosso, ecc ...

Affinché questo esempio funzioni, devi assicurarti di avere sempre i --color=alwaystuoi comandi grep. Ho impostato questo nel mio .bashrc modo che grep abbia sempre i colori:

export GREP_OPTIONS='--color=always'


Quello che sto tentando di realizzare è avvolgere questa funzionalità con un alias in modo da poter semplicemente chiamare grepe avere un GREP_COLORSvalore diverso ogni volta. Comprendo la considerazione di più shell per ogni nuovo grep convogliato e sto provando a superare questo creando alcuni file (uno per ogni colore), per indicare che sono già stati utilizzati.

Ho fatto alcuni tentativi, ma stranamente, questo sembra funzionare al meglio. Ho questo nel mio .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 "$@"
}

Sto usando questo alias in questo modo:

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

I risultati sono piuttosto interessanti. Vi sono tuttavia alcuni errori che sono leggermente diversi ogni volta. Ecco un paio di schermate:

Sembra che mentre la shell passa attraverso ogni comando pipe, la funzione precedente non ha ancora terminato la sua esecuzione. Cerca di rimuovere i file che non esistono più. Non sono troppo sicuro da dove command not foundprovengano quegli altri errori.

Come puoi vedere, ho inserito alcuni waitcomandi per provare a completare la manipolazione del file, ma questo non sembra funzionare troppo bene. Un'altra cosa che ho già provato è usare la memoria condivisa /dev/shmma ha prodotto risultati simili.

Come farei per ottenere i risultati desiderati?

Nota:

Sto cercando risposte che semplicemente racchiudano il comando grep in quanto ha molte funzionalità che voglio usare e intendo inserire altra logica tra le pipe, quindi non voglio fornire tutti i termini di ricerca contemporaneamente. Inoltre non sto cercando altri strumenti "grep like". Mi dispiace per @terdon che ha già pubblicato un fantastico suggerimento perl.


Il tuo primo esempio non corrisponde a quello che stai spiegando nella parte rimanente, semplicemente dicendo.
Bernhard

@bernhard Non capisco cosa intendi .. La mia intenzione è quella di usare il mio alias come parte di un comando più grande usando il piping ... Per favore fatemi sapere di quale contraddizione stai parlando ...
Lix

Pensavo volessi usare anche il tuo alias al di fuori delle pipe. Comunque, il tuo primo esempio non funziona per me. Ci hai provato alias mg="mygrep; grep"?
Bernhard

@Bernhard - Sto lavorando su una scatola Ubuntu 12.04. Non sarei sorpreso se ci fossero lievi differenze ... Ho provato il tuo suggerimento, il problema è che mygrep;si trasforma in un nuovo comando in sé e il flusso di dati si perde. La pipa in arrivo da lsverrebbe passata mygrep;e non grep. Almeno è così che lo capisco.
Lix,

@ Bernard - Ah .. penso di sapere perché non ha funzionato per te. Devi assicurarti di avere --color=alwaystutti i tuoi comandi grep. L'ho impostato a livello globale nel mio .bashrc. L'ho modificato nel post.
Lix,

Risposte:


6

Ecco un approccio diverso. Ho un piccolo script Perl che ho già pubblicato in un'altra risposta che metterà in evidenza i modelli forniti dall'utente in diversi colori. Una versione leggermente modificata dello script agirà come 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;
}

Se si salva quello script come cgrepda qualche parte nel proprio PATHe lo si rende eseguibile, è possibile specificare fino a 10 diversi modelli, ognuno dei quali verrà stampato in un colore diverso:

inserisci qui la descrizione dell'immagine

$ 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;

5

Ogni invocazione di grepin una pipe viene eseguita in una shell separata, quindi dovrai passare uno stato tra di loro. La seguente soluzione è un modo grezzo per gestirlo con un file che mantiene l'indice di colore e un file di blocco che garantisce che le chiamate simultanee non leggano lo stesso valore:

#!/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 "$@"

Prova supponendo che tu abbia nominato la tua copia cgrepe mettila sul tuo PATH:

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz

Le uniche variabili che devono davvero essere mantenute sono COLOR_INDEXe GREP_COLORS. Ho provato a esportarli alla fine della funzione senza successo. È quello che volevi dire? Semplicemente avere export VAR, giusto?
Lix,

Oh - e sì .. errore di battitura stupido lì con COLOR_TOGGLE. Grazie per averlo
beccato

1
@ l0b0 Anche l'esportazione non funziona per me, per il momento è necessario effettuare il downgrade fino a quando non risponde davvero alla domanda.
Bernhard

@ Bernard Questo funziona per te?
l0b0

Grazie per il tuo contributo! Ho incorporato il tuo grep "$@"suggerimento - che ha risolto l'alias per eseguire la funzione e quindi grep.
Lix,

1

Se sei bravo con le espressioni regolari, potresti voler dare un'occhiata a grc e grcat. grc chiama grcat.

grcat utilizza file di configurazione in cui è possibile aggiungere espressioni regolari per abbinare il testo da visualizzare in ciascun colore. Ha anche una serie di altre opzioni. L'impostazione predefinita è la colorazione dei file di registro di sistema.

A seconda di ciò che hai in mente per lo script finale, potresti essere in grado di colorare il tuo output con un solo comando.

Il trucco sta nel specificare correttamente le regex per ogni "campo" nella tua fonte di dati. Questo sarà molto più semplice se i tuoi dati sono relativamente uniformi nella struttura.

L'ultima volta che l'ho provato, non sono andato troppo lontano, ma potrei fare un altro tentativo perché sono un po 'più bravo nelle regex di quanto non fossi allora.

C'è anche il comando tput che può essere utilizzato per inviare informazioni (come i cambi di colore) direttamente al dispositivo terminale.

Entrambi gli approcci sono coperti dal post seguente. Parla del comando find, ma può essere applicato all'output di qualsiasi comando.

FIND colorato?

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.