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
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.
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}" ; }
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
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.
En lugar de usar Grep, puede usar Less:
less file
Buscar así: /pattern
Enter
Esta voluntad:
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.
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.
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.
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 usandorg "^|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.
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í .
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]"
}
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 interpretadosCon 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".