Cómo truncar largas líneas coincidentes devueltas por grep o ack

90

Quiero ejecutar ack o grep en archivos HTML que a menudo tienen líneas muy largas. No quiero ver filas muy largas que se envuelven repetidamente. Pero quiero ver solo esa parte de una línea larga que rodea una cadena que coincide con la expresión regular. ¿Cómo puedo obtener esto usando cualquier combinación de herramientas Unix?

dan
fuente
1
¿Qué es ack? ¿Es un comando que usa cuando no le gusta algo? Algo como ack file_with_long_lines | grep pattern? :-)
Alok Singhal
6
@Alok ack(conocido como ack-grepDebian) usa grepesteroides. También tiene la --thppptopción (no es broma). betterthangrep.com
ZoogieZork
Gracias. Hoy aprendí algo.
Alok Singhal
1
Mientras que la --thppptcaracterística es algo controvertido, la ventaja clave parece ser que puede utilizar expresiones regulares Perl directamente, no un loco [[:space:]]y personajes como {, [, etc. cambiando el significado con el -ey -Ecambia de una manera que es imposible recordar.
Evgeni Sergeev

Respuestas:

99

Puede usar la opción grep -o, posiblemente en combinación con cambiar su patrón ".{0,10}<original pattern>.{0,10}"para ver algo de contexto a su alrededor:

       -o, --sólo coincidencia
              Muestre solo la parte de una línea coincidente que coincida con PATTERN.

..o -c:

       -c, --contar
              Suprime la salida normal; en su lugar imprime un recuento de líneas coincidentes
              para cada archivo de entrada. Con la opción -v, --invert-match (ver
              a continuación), cuente las líneas que no coinciden.
Éter
fuente
44
un ejemplo: grep -oE ". {0,20} mysearchstring. {0,20}" myfile
Renaud
14
debe cambiar la respuesta para agregar la opción -E como lo muestra @Renaud (opción de patrón extendido), o el patrón propuesto para extender el contexto no funcionará.
kriss
Quizás no sea tan necesario, pero aquí hay un ejemplo: $ echo "eeeeeeeeeeeeeeeeeeeeqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrrrr" > fileonelongline.txt && grep -oE ".{0,20}MYSTRING.{0,20}" ./fileonelongline.txt impresionesqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwww
Ulises Layera
Esto funciona bien; pero la desventaja notable es que cuando se usa, por ejemplo, oE ".{0,20}mysearchstring.{0,20}"se pierde el resaltado de la cadena "original" interna en el contexto, porque todo se convierte en el patrón de búsqueda. Me encantaría encontrar una manera de mantener un contexto no resaltado alrededor de los resultados de búsqueda, para un escaneo visual y una interpretación de resultados mucho más fáciles.
Aaron Wallentine
1
Oh, aquí hay una solución al problema de resaltado causado por el uso del -oE ".{0,x}foo.{0,x}"enfoque (donde xestá el número de caracteres del contexto) - append `| grep foo `hasta el final. Funciona para soluciones ack o grep. Más soluciones también aquí: unix.stackexchange.com/questions/163726/…
Aaron Wallentine
44

Transmita sus resultados cut. También estoy considerando agregar un --cutinterruptor para que pueda decir --cut=80y obtener solo 80 columnas.

Andy Lester
fuente
8
¿Qué pasa si la parte que coincide no está en los primeros 80 caracteres?
Ether
3
FWIW Lo agregué | cut=c1-120al grep, funcionó para mí (aunque no sé cómo cortar el texto coincidente)
Jake Rayson
26
| cut=c1-120no funcionó para mí, necesitaba hacerlo| cut -c1-120
Ken Cochrane
1
Creo que @edib es preciso en la sintaxis | cut -c 1-100 stackoverflow.com/a/48954102/1815624
CrandellWS
1
@AndyLester: ¿Qué pasa con una --no-wrapopción que usa $COLUMNS?
naught101
25

Podría usar menos como buscapersonas para ack y cortar líneas largas: ack --pager="less -S" esto retiene la línea larga pero la deja en una línea en lugar de envolverla. Para ver más de la línea, desplácese hacia la izquierda / derecha en menos con las teclas de flecha.

Tengo la siguiente configuración de alias para que ack haga esto:

alias ick='ack -i --pager="less -R -S"' 
Jonah Braun
fuente
2
Tenga en cuenta que puede poner ese --pagercomando en su archivo ~ / .ackrc, si siempre quiere usarlo.
Andy Lester
Esto suena como la mejor solución con diferencia a este problema que me molesta mucho. Ojalá supiera cómo usarlo ack.
Brian Peterson
@BrianPeterson ackes prácticamente igual grep, solo que más simple en los casos más comunes
Aaron Wallentine
8
cut -c 1-100

obtiene caracteres del 1 al 100.

edib
fuente
2

Tomado de: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/

El enfoque sugerido ".{0,10}<original pattern>.{0,10}"es perfectamente bueno, excepto que el color de resaltado a menudo está desordenado. Creé un script con una salida similar, pero el color también se conserva:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the
# matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 |
grep --color=none -oE \
    ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

Suponiendo que la secuencia de comandos se guarda como grepl, entonces grepl pattern file_with_long_linesdebería mostrar las líneas coincidentes pero con solo 10 caracteres alrededor de la cadena coincidente.

xuhdev
fuente
Funciona, pero me da como resultado basura final, así: ^ [[? 62; 9; c. No he intentado depurar porque la respuesta de @Jonah Braun me satisfizo.
sondra.kinsey
1

Esto es lo que hago:

function grep () {
  tput rmam;
  command grep "$@";
  tput smam;
}

En mi .bash_profile, que anulan grep para que se ejecute automáticamente tput rmamantes y tput smamdespués de que personas con discapacidad envoltura y luego re-habilita.

ognockocaten
fuente
Esa es una buena alternativa, excepto si la coincidencia real está fuera de la pantalla ...
Xerus
1

ingrese la descripción de la imagen aquí

En la situación inusual en la que no puede usar -E, puede usar:

grep -oe ".\{0,10\}error.\{0,10\}" mylogfile.txt
Josh Withee
fuente
0

Puse lo siguiente en mi .bashrc:

grepl() {
    $(which grep) --color=always $@ | less -RS
}

Luego puede usar greplen la línea de comando con cualquier argumento que esté disponible para grep. Utilice las teclas de flecha para ver la cola de las líneas más largas. Úselo qpara salir.

Explicación:

  • grepl() {: Defina una nueva función que estará disponible en cada (nueva) consola bash.
  • $(which grep): Obtenga la ruta completa de grep. (Ubuntu define un alias para grepeso es equivalente a grep --color=auto. No queremos ese alias sino el original grep).
  • --color=always: Colorea la salida. ( --color=autoel alias no funcionará ya grepque detecta que la salida se coloca en una tubería y no la coloreará en ese momento).
  • $@: Pon todos los argumentos dados a la greplfunción aquí.
  • less: Muestra las líneas usando less
  • -R: Mostrar colores
  • S: No rompa largas filas
pt1
fuente