“Grep” que resalta en lugar de filtrar

Me preguntaba si hay un programa en el conjunto de herramientas comunes de Unix, como grep, que en lugar de filtrar las líneas que contienen una cadena, simplemente genera la misma entrada pero resalta o colorea la cadena seleccionada.

Estaba pensando en hacerlo yo mismo (debería ser lo suficientemente simple), pero tal vez ya existe como un comando de Unix.

Estoy planeando usarlo para monitorear registros, así que haría algo como esto:

tail -f logfile.log | highlight "error"

Por lo general, cuando estoy monitoreando registros, necesito encontrar una cadena en particular, pero también necesito saber qué está escrito antes y después de la cadena, por lo que filtrar a veces no es suficiente.

Algo como eso existe?

Gracias

Prácticamente respondido aquí: stackoverflow.com/questions/981601/…
Esto me parece fuera de tema, ya que no está solicitando una aplicación. Sin duda, sería mejor preguntar en unix.stackexchange.com

Respuestas (14)

Este es un truco divertido para ello con el grepcomando básico. Consiste en utilizar dos filtros: el que desea aplicar y uno ficticio que iguala todas las líneas pero no produce ningún resaltado. Esta coincidencia ficticia puede ser ^(comienzo de línea) o $(final de línea).

grep "^\|text" --color='always' file

o

grep -E "^|text" --color='always' file

Vea un ejemplo:

$ cat a
hello this is 
some text i wanted
to share with you
$ grep "^\|text" --color='always' a
hello this is 
some text i wanted     # "text" is highlighted
to share with you
Parece que ni siquiera necesita ^o $y simplemente "|text"funciona también.

Hay una herramienta llamada ack. Puede encontrarlo en http://beyondgrep.com y, de hecho, es una herramienta más allá de grep. Su uso más común es el relleno de ese papel find . -name "*.java" --print | xargs grep clazzo similar. Porque hacemos eso todo el tiempo.

Solo ack clazzy obtienes la salida. Busca los archivos adecuados (no se molesta en tratar de grep binarios) y también ofrece una buena salida de color.

Si lo usa con la --passthruopción, imprimirá todo el flujo de entrada, resaltando las regiones coincidentes en color.

--passthruImprimir todas las líneas, ya sea que coincidan o no

Como indica la documentación, si -se usa para el archivo, se necesitará STDIN:

Si se especifican archivos o directorios, solo se comprueban esos archivos y directorios. ack también puede buscar STDIN, pero solo si no se especifica ningún argumento de archivo o directorio, o si uno de ellos es "-".

Por lo tanto, perdone el catabuso ( y el juego de palabras, vea a continuación ), puede tenerlo:

$ cat file | ack --passthru pattern
$ cat file | ack --passthru pattern -

Esto tomará la salida de la tubería y la enviará a través de ackla cual imprimirá todas las líneas (con --passthru) con el patrón resaltado.

Esta es exactamente la herramienta que está buscando (y un poco más). Es un paquete estándar para muchos administradores de paquetes. Consulte http://beyondgrep.com/install/ para conocer su favorito.

_ /|
\'oO'
=(___)=
   ¡Cuidado, thpppt!

(Si no lo reconoce, ese es Bill the Cat , aunque la búsqueda de imágenes también podría ayudar, no haga clic en el conjunto de Miley Cyrus)

Ack es una gran herramienta, pero ¿cómo puede imprimir toda su entrada simplemente resaltando el patrón de búsqueda? Normalmente se usa como una forma de orientación grep -R, como explica, no veo cómo puede ayudar al OP.
@terdon la --passthruopción imprimirá todas las líneas y resaltará los patrones de interés. Del mismo modo, para trabajar en STDIN, se puede usar el guión como el 'nombre' del archivo, o ningún argumento de archivo.
Ya veo, eso tiene sentido. Como dijiste que actúa como grep, asumí que solo imprimiría la línea coincidente.
@terdon su modo predeterminado es grepy. Aunque, como la gente ha estado señalando con otras opciones, se puede engañar a grep para que imprima todas las líneas y resalte el texto de interés. ack no necesita ser engañado para hacer eso, es una de las opciones estándar. Y gracias por la edición aclaratoria.

Puede usar la grep -Cbandera que da n líneas de contexto, por ejemplo grep -C 3, imprimirá las 3 líneas antes y después del partido. Los hay también -By -Apara antes y después.

Si está buscando resaltar cadenas dadas regularmente, por ejemplo, formatos de registro específicos, podría valer la pena usar python pygmentize con un lexer personalizado , ya que está basado en expresiones regulares, se sorprenderá de lo fácil que es . Este último también tiene la ventaja de ser multiplataforma aunque algunos terminales no funcionan muy bien con el color.

Soy fan de hhighlighter de Paolo Antinori. https://github.com/paoloantinori/hhighlighter

Un lado positivo de este comando es que puede resaltar hasta 10 palabras con colores únicos. Simplemente canalice la salida de un comando hcon las palabras para resaltar.

Por ejemplo tail -f /var/log/somelog.log | h "ERROR", producirá:

demostración-1


Algunos ejemplos de su sitio:

demostración-2 demostración-3

He escrito un pequeño script que coloreará cualquier cadena que le des:

#!/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_magenta', 
           'bright_white on_red', '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=<>) 
{ 
    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;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
        }
      }
    }
    print STDOUT $line;
}

Si lo guarda como coloren un directorio que está en su $PATHy lo hace ejecutable ( chmod +x /usr/bin/color), puede colorear el patrón coincidente de esta manera:

echo -e "foo\nbar\nbaz\nbib" | color -l foo,bib 

Eso producirá:

  ingrese la descripción de la imagen aquí

Tal como está escrito, el script tiene colores predefinidos para 10 patrones diferentes, por lo que darle una lista separada por comas como en el ejemplo anterior coloreará cada uno de los patrones combinados en un color diferente.

Escribí un programa para hacer esto hace algún tiempo. Lo llamo cgrep (por color grep).

Puede descargarlo copiando la sección del código desde aquí en un archivo vacío: http://wiki.tcl.tk/38096

Luego haga que el archivo sea ejecutable y cópielo en uno de sus directorios bin regulares.

Está escrito en tcl, por lo que necesita tcl instalado (8.5 y superior). Pero la mayoría de las distribuciones de Linux tendrían tcl instalado de todos modos, ya que muchos programas lo usan (gitk, kernel config, expect, etc.).

La sintaxis para colorear es simple: regex option option ... Puede tener tantas expresiones regulares como desee. Aquí hay un ejemplo que colorearía los errores en rojo y las advertencias en amarillo:

tail -f logfile | cgrep '^.*WARNING.*$' -fg yellow '^.*ERROR.*$' -fg red -bg yellow

La forma más fácil se ve así, creo:

tail -f logfile.log | grep -e 'error' -e '**'

ingrese la descripción de la imagen aquí

No es necesario instalar nada.

Bueno, estoy ejecutando Fedora 21 y si escribo

grep -E \|kk rs.c

generará todo el contenido del archivo "rs.c" mientras resalta cualquier aparición de "kk".

Eso es básicamente lo mismo que la respuesta de arielCo .
@Izzy: Sin embargo, la sintaxis es más corta, por lo que diría que califica como una respuesta válida diferente.
@NicolasRaoul es por eso que solo dejé un comentario en ese entonces (pero no marqué). Básicamente, esperaba que el póster se expandiera un poco;)

Puedes usar este comando

grep --color --context=1000

o más corto

grep --col -1000

explicashell.com - grep --color --contexto

Un truco simple es hacer coincidir también una cadena vacía o el comienzo de una línea; cualquiera da como resultado una coincidencia de longitud cero para todas las líneas:

grep --color -e 'REGEXP' -e ''
grep --color -e 'REGEXP' -e ^

O (sintaxis extendida de expresiones regulares):

grep --color -E 'REGEXP|'
egrep --color 'REGEXP|'
¿La primera variante no filtraría REGEXtambién la salida? Acabo de probar, y lo hace. Entonces eso no coincide con los requisitos (solo resaltar, no filtrar). Pero la segunda variante de hecho hace lo que solicitó el OP (verificado;).
Sí, eso tiene sentido ahora :) Filtro para REGEX(resalta ese término) y para "nada" (que es "en todas partes"). ¿Puedo sugerirle que incluya esta pequeña explicación (también aclare lo que hace), y luego eliminemos nuestros comentarios (para limpieza)? ¡Gracias! Mientras tanto +1 de mí :)
Lo haré, pero Fedorqui dio esencialmente la misma respuesta anterior (supongo que no la vi cuando publiqué la mía).
Tengo que admitir que tampoco lo vi... (pista: no hay "arriba" o "abajo", ya que el orden de las respuestas depende del filtro que hayas configurado;)

uso less_ La cadena de búsqueda encontrada por /es una expresión regular y las ocurrencias se resaltarán.

En mi .bashrc tengo esta función. Lo llamo cgrep, pero le estoy dando un nombre un poco más apropiado aquí.

highlight() { grep -E --color "^|$1"; }

Encuentro esto útil para registros de seguimiento, por ejemplo, donde quiero resaltar una palabra clave pero veo todo lo que sucede.

tail -f /var/log/SOMELOG | highlight KEYWORD
Debido crédito: obtuve el "^|" idea de la respuesta seleccionada de @fedorqui. Gracias :)

Simplemente puede canalizar su salida a:

sed "s/\([Ee][Rr][Rr][Oo][Rr]\)/`tput rev`\1`tput rmso`/"

Aquí estoy usando una expresión regular que coincidirá con "error", "ERROR", "ErRoR", etc. en las 32 variaciones posibles.

Tengo la siguiente función definida en mi ~/.zshrc:

hl () {
    sed s/$1/$'\e[1;31m'\&$'\e[0;m'/
}

Úsalo con tail -f logfile.log | hl "error". Agrega una secuencia de escape para Light Red antes de la palabra resaltada y restablece sin color después de la palabra. Puede encontrar otros códigos de color aquí: http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html