it-swarm-es.tech

Convencer a grep para generar todas las líneas, no solo aquellas con coincidencias

Digamos que tengo el siguiente archivo:

$ cat test

test line 1
test line 2
line without the search Word
another line without it
test line 3 with two test words
test line 4

Por defecto, grep devuelve cada línea que contiene el término de búsqueda:

$ grep test test

test line 1
test line 2
test line 3 with two test words
test line 4

Pasando el --color parámetro a grep lo hará resaltar la parte de la línea que coincide con la expresión de búsqueda, pero aún así solo devuelve líneas que contienen la expresión. ¿Hay alguna manera de hacer que grep muestre todas las líneas del archivo fuente, pero resalte las coincidencias?

Mi truco terrible actual para lograr esto (al menos en archivos que no tienen más de 10000 líneas consecutivas sin coincidencias) es:

$ grep -B 9999 -A 9999 test test

Screenshot of the two commands

Si grep no puede lograr esto, ¿hay otra herramienta de línea de comandos que ofrezca la misma funcionalidad? He jugado con ack , pero tampoco parece tener una opción para ello.

127
Michael Mrozek
grep --color -E "test|$" yourfile

Lo que estamos haciendo aquí es hacer coincidir el $ patrón y patrón de prueba, obviamente $ no tiene nada que colorear, por lo que solo el patrón de prueba adquiere color. Los -E solo activa la coincidencia de expresiones regulares extendida.

Puede crear una función fácilmente de esta manera:

highlight () { grep --color -E "$1|$" "${@:1}" ; }
194
jacksonh
ack --passthru --color string file

para Ubuntu y Debian, use ack-grep en lugar de ack

ack-grep --passthru --color string file

Otra forma de hacer esto correctamente y de forma portátil con grep (además de usar dos expresiones regulares con alternancia como en la respuesta aceptada) es a través del patrón nulo (y respectivamente la cadena nula).
Debería funcionar igualmente bien con ambos -E y -F cambia desde, según el estándar :

-E
    Match using extended regular expressions. 
    [...] A null ERE shall match every line.

y

-F
    Match using fixed strings.
    [...] A null string shall match every line.

Entonces es simplemente una cuestión de correr

grep -E -e '' -e 'pattern' infile

y respectivamente

grep -F -e '' -e 'string' infile
13
don_crissti

Tengo la siguiente función que uso para tales cosas:

highlight () {
    Perl -pe "s/$1/\e[1;31;43m$&\e[0m/g"
}

Internamente se ve un poco feo, es agradable y fácil de usar, así:

cat some_file.txt | highlight some_Word

o, para un ejemplo un poco más real:

tail -f console.log | highlight ERROR

Puedes cambiar los colores a lo que quieras (que puede ser difícil con grep, no estoy seguro) cambiando el 1 y 31 y 43 (después \e[) a diferentes valores. Los códigos para usar son todos sobre el lugar , pero aquí hay una introducción rápida: el 1 en negrita el texto, el 31 lo hace rojo, y el 43 da un fondo amarillo. 32 o 33 sería de diferentes colores, y 44 o 45 serían fondos diferentes: se entiende la idea. Incluso puedes hacer que parpadee (con un 5) si estás tan inclinado.

Esto no utiliza ningún módulo especial de Perl, y Perl es casi ubicuo, por lo que esperaría que funcione en cualquier lugar. La solución grep es muy inteligente, pero el interruptor --color en grep no está disponible en todas partes. Por ejemplo, acabo de probar esta solución en una caja de Solaris que ejecuta bash, y otra que ejecuta ksh, y mi máquina Mac OS X local ejecuta zsh. Todo funcionó bien. Solaris se atragantó con el grep --color solución, sin embargo.

Además, ack es increíble, y lo recomiendo a cualquiera que aún no lo haya descubierto, pero he tenido algunos problemas para instalarlo en algunos de los muchos servidores en los que trabajo. (Olvidé por qué: creo que relacionado con los módulos de Perl requería).

Como no creo que haya trabajado en un cuadro de Unix que no funcionó tiene instalado Perl (con la excepción de los sistemas de tipo embebido, los enrutadores Linksys y demás). Diría que esta es una solución prácticamente universal.

11
iconoclast

En lugar de usar Grep, puede usar Less:

less file

Buscar así: /pattern Enter

Esta voluntad:

  1. desplazarse a la primera línea coincidente
  2. salida de cada línea a partir de ahí en adelante
  3. resaltar todos los partidos

Para desplazarse a la siguiente línea coincidente: n

Para desplazarse a la línea coincidente anterior: N

Para alternar el resaltado: Esc u

También puede cambiar el color de resaltado si lo desea.

3
Steven Penny

Puedes probar:

Perl -MTERM::ANSIColor -nle '/pattern/ ? print colored($_, 'color') : print' test

Sin embargo, no es muy portátil, e incluso si Perl está instalado, es posible que deba descargar otro módulo. Además, coloreará toda la línea, no solo la palabra de búsqueda.

2
gvkv

Ninguna de las respuestas proporcionadas hasta ahora proporciona una solución portátil .

Aquí hay un portátil1 Función de shell I ya publicada en una pregunta cerrada como duplicada que no requiere herramientas no estándar o extensiones no estándar provistas con Perl, ack, ggrep, gsed, bash y los me gusta, pero solo necesita un Shell POSIX y las utilidades obligatorias POSIX sed y printf:

grepc()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed 's"'"$pattern"'"'$esc'[32m&'$esc'[0m"g' "[email protected]"
}

Puedes usarlo de esa manera:

grepc string_to_search [file ...]

El color de resaltado se puede ajustar usando uno de estos códigos en el argumento del comando sed (32m es verde aquí):

30m black
31m red
33m yellow
34m blue
35m Magenta
36m cyan
37m white
7m reverse video

1 Siempre que su terminal admita secuencias de escape de colores ANSI.

2
jlliagre

ripgrep

Use ripgrep con su --passthru parámetro:

rg --passthru pattern file.txt

Es una de las herramientas de grepping más rápidas , ya que está construida sobre motor regex de Rust que utiliza autómatas finitos, SIMD y optimizaciones literales agresivas para que la búsqueda sea muy rápida.

--passthru - Imprime líneas coincidentes y no coincidentes.

Otra forma de lograr un efecto similar es modificando su patrón para que coincida con la cadena vacía. Por ejemplo, si está buscando usando rg foo luego usando rg "^|foo" en su lugar emitirá cada línea en cada archivo buscado, pero solo se resaltarán las apariciones de foo. Este indicador habilita el mismo comportamiento sin necesidad de modificar el patrón.

2
kenorb

Hay una manera mucho más fácil de hacer esto para GNU grep pero no creo que sea portátil (es decir, BSD grep):

En una tubería:

cat <file> | grep --color=always -z <query>

En un archivo:

grep --color=always -z <query> <file>

El crédito va a la respuesta de Cyrus aquí .

1
Erik Nomitch

Una versión sed, funciona tanto en bash como en ash.

#highlight
hsed(){
    local pattern="$1"
    shift
    local r=`echo -e '\e'[31m`
    local c=`echo -e '\e'[0m`
    sed "s:${pattern//:/\:}:$r\0$c:g" "[email protected]"
}
0
yurenchen

OP solicitó grep, y eso es lo que RECOMIENDO; pero después de intentar resolver un problema con sed, para el registro, aquí hay una solución simple:

sed $'s/main/\E[31m&\E[0m/g' testt.c

o

cat testt.c | sed $'s/main/\E[31m&\E[0m/g'

Pintará main en rojo.

  • \E[31m: secuencia de inicio de color rojo
  • \E[0m: marca de color terminada
  • &: el patrón coincidente
  • /g: todas las palabras en una línea, no solo la primera
  • $'string' son cadenas bash con caracteres escapados interpretados

Con respecto a grep, también funciona usando ^ (comienzo de línea) en lugar de $ (fin de la línea). Ejemplo:

egrep "^|main" testt.c

Y solo para mostrar este alias loco que NO RECOMIENDO, incluso puedes dejar las comillas abiertas:

alias h='egrep -e"^|'
h main" testt.c
cat testt.c | h main"

¡todo el trabajo! :) No se preocupe si olvida cerrar la cita, bash lo recordará con un "carácter de línea continua".

0
Dr Beco