Grep multicolor

30

Estoy tratando de hacer que cada comando grep resalte sus resultados en un color diferente. Puedo hacerlo manualmente con una línea como esta:

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

Cada cpersonaje se resaltará en verde y cada opersonaje se resaltará en rojo, etc.

Para que este ejemplo funcione, deberá asegurarse de tener siempre --color=alwayssus comandos grep. He configurado esto en mi .bashrc grep siempre tendrá colores:

export GREP_OPTIONS='--color=always'


Lo que intento lograr es envolver esta funcionalidad con un alias para poder llamar grepy tener un GREP_COLORSvalor diferente cada vez. Entiendo la consideración de múltiples shells para cada nuevo grep entubado y estoy tratando de superar esto creando algunos archivos (uno para cada color), para indicar que ya se han utilizado.

He hecho algunos intentos, pero extrañamente, este parece funcionar "lo mejor". Tengo esto en mi .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 "$@"
}

Estoy usando este alias así:

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

Los resultados son bastante geniales. Sin embargo, hay algunos errores que son ligeramente diferentes cada vez. Aquí hay un par de capturas de pantalla:

Parece que a medida que el shell pasa por cada comando de tubería, la función anterior aún no terminó su ejecución. Intenta eliminar archivos que ya no existen. No estoy muy seguro de dónde command not foundprovienen esos otros errores.

Como puede ver, he puesto algunos waitcomandos para intentar dejar que se complete la manipulación del archivo, pero esto no parece funcionar demasiado bien. Otra cosa que ya he intentado es usar memoria compartida /dev/shmpero arrojó resultados similares.

¿Cómo haría para obtener los resultados que quiero?

Nota:

Estoy buscando respuestas que simplemente envuelvan el comando grep, ya que tiene muchas funciones que quiero usar e intento insertar otra lógica entre las tuberías, por lo que no quiero proporcionar todos los términos de búsqueda a la vez. Tampoco estoy buscando otras herramientas "grep like". Perdón por @terdon que ya ha publicado una increíble sugerencia de perl.

Lix
fuente
Su primer ejemplo no coincide con lo que está explicando en la parte restante, solo dice.
Bernhard
@bernhard No entiendo lo que quieres decir ... Mi intención es usar mi alias como parte de un comando más grande usando tuberías ... Por favor, hágame saber de qué contradicción está hablando ...
Lix
Pensé que también querías usar tu alias fuera de las tuberías. De todos modos, tu primer ejemplo no funciona para mí. ¿Lo intentaste alias mg="mygrep; grep"?
Bernhard
@Bernhard: estoy trabajando en una caja ubuntu 12.04. No me sorprendería si hubiera pequeñas diferencias ... Intenté su sugerencia, el problema con eso es que se mygrep;convierte en un nuevo comando en sí mismo y el flujo de datos se pierde. La tubería entrante de la lspasaría a mygrep;y no a grep. Al menos así es como lo entiendo.
Lix
@Bernhard - Ah ... creo que sé por qué no funcionó para ti. Debe asegurarse de tener --color=alwaystodos sus comandos grep. Lo he establecido globalmente en mi .bashrc. Lo he editado en la publicación.
Lix

Respuestas:

6

Aquí hay un enfoque diferente. Tengo un pequeño script de Perl que ya publiqué en otra respuesta que resaltará los patrones proporcionados por el usuario en diferentes colores. Una versión ligeramente modificada del script actuará como 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 guarda esa secuencia de comandos como cgrepparte de su PATHy la hace ejecutable, puede especificar hasta 10 patrones diferentes, cada uno de los cuales se imprimirá en un color diferente:

ingrese la descripción de la imagen aquí

$ 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
fuente
5

Cada invocación de grepen una tubería se ejecuta en un shell separado, por lo que deberá pasar algún estado entre ellos. La siguiente solución es una forma cruda de manejar eso con un archivo que mantiene el índice de color y un archivo de bloqueo que garantiza que las llamadas simultáneas no lean el mismo valor:

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

Pruebe suponiendo que ha nombrado su copia cgrepy póngala en su PATH:

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz
l0b0
fuente
Las únicas variables que realmente necesitan ser mantenidas son COLOR_INDEXy GREP_COLORS. Intenté exportarlos al final de la función sin éxito. ¿Es eso lo que querías decir? Simplemente para tener export VAR, ¿verdad?
Lix
Ah, y sí ... error tipográfico allí con COLOR_TOGGLE. Gracias por atraparlo :)
Lix
1
@ l0b0 La exportación tampoco funciona para mí, tengo que votar a favor por ahora hasta que realmente responda la pregunta.
Bernhard
@ Bernhard ¿Funciona esto para usted?
l0b0
¡Gracias por tu contribución! He incorporado su grep "$@"sugerencia, que resolvió el alias para ejecutar la función y luego grep.
Lix
1

Si eres bueno con las expresiones regulares, es posible que desees consultar grc y grcat. grc llama grcat.

grcat utiliza archivos de configuración donde puede agregar expresiones regulares para que coincidan con el texto que se mostrará en cada color. También tiene una serie de otras opciones. El valor predeterminado es colorear los archivos de registro del sistema.

Dependiendo de lo que tenga en mente para su script final, es posible que pueda colorear su salida con solo un comando.

El truco es especificar las expresiones regulares correctamente para cada "campo" en su fuente de datos. Esto será mucho más fácil si sus datos tienen una estructura relativamente uniforme.

La última vez que lo probé, no llegué demasiado lejos, pero es posible que tenga otra oportunidad porque soy un poco mejor en expresiones regulares de lo que era entonces.

También está el comando tput que se puede usar para enviar información (como cambios de color) directamente a su dispositivo terminal.

Ambos enfoques están cubiertos por la publicación a continuación. Habla sobre el comando find, pero se puede aplicar a la salida de cualquier comando.

Color ENCONTRAR salida?

Joe
fuente