Grep solo el primer partido y detente


329

Estoy buscando un directorio recursivamente usando grep con los siguientes argumentos con la esperanza de devolver solo la primera coincidencia. Desafortunadamente, devuelve más de uno, de hecho, dos la última vez que miré. Parece que tengo demasiados argumentos, especialmente sin obtener el resultado deseado. : - /

# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory

devoluciones:

Pulsanti Operietur
Pulsanti Operietur

¿Quizás grep no es la mejor manera de hacer esto? Dime, muchas gracias.

Respuestas:


512

-m 1significa devolver la primera coincidencia en cualquier archivo dado. Pero aún continuará buscando en otros archivos. Además, si hay dos o más coincidencias en la misma línea, se mostrarán todas.

Puede usar head -1para resolver este problema:

grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1

explicación de cada opción grep:

-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively

¡increíble! gracias. por cierto, ¿son necesarios todos esos otros argumentos que tengo en el comando? y qué pasa si no puedo canalizarlo por casualidad (por si acaso).
Tim Kamm

2
No creo que sean necesarios (excepto -robviamente), pero no deberían doler ( -aaunque no lo usaría )
MVP

3
Exactamente lo que necesitaba. Mi patrón se encontró dos veces en la misma línea y grep -m 1devolvió ambas instancias debido a esto. |head -1¡resuelto!
Harperville

66
@Chris_Rands el comportamiento exacto depende del shell en el que se está ejecutando. Head saldrá tan pronto como encuentre la primera línea. grep saldrá la próxima vez que intente escribir después de que head haya salido. Algunos proyectiles esperarán hasta que finalicen todos los elementos de una tubería, algunos harán que se cierre la tubería completa tan pronto como salga el último programa de la tubería.
puhlen

1
@ 3QN, no entiendo tu comentario: first not first from result. Esta respuesta imprime la primera coincidencia en cualquier archivo y se detiene. ¿Qué otra cosa esperabas?
mvp

31

Puede canalizar el grepresultado headjunto con stdbuf .

Tenga en cuenta que para asegurarse de detenerse después de la enésima coincidencia, debe usar stdbufpara asegurarse de grepno almacenar en búfer su salida:

stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1

Tan pronto como headconsume 1 línea, finalizó y greprecibirá SIGPIPEporque todavía emite algo a la tubería mientras headestaba fuera.

Esto supone que ningún nombre de archivo contiene nueva línea.


Estoy tratando de adoptar esta solución para buscar en un gran número de archivos de almacenamiento con xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. Esto, sin embargo, no termina en el primer partido. ¿Algún consejo?
DKroot

1
¿ grepLa --line-bufferedopción no evitaría la sobrecarga del búfer sin llamar a una utilidad adicional?
David

23

Mi programa grep-a-like acktiene una -1opción que se detiene en la primera coincidencia encontrada en cualquier lugar. Es compatible con el -m 1que @mvp también se refiere. Lo puse allí porque si estoy buscando un gran árbol de código fuente para encontrar algo que sé que existe en un solo archivo, no es necesario encontrarlo y tener que presionar Ctrl-C.


¿Entonces dirías que ack es más rápido que grep? Estoy realmente preocupado por el factor de velocidad también.
Tim Kamm

1
ack puede ser más rápido que grep, dependiendo de lo que esté buscando. Tenga en cuenta que ack se trata de buscar el código fuente. Si está buscando buscar archivos generales, es menos bueno para eso, al menos en ack 1.x. Lea sobre ack y vea si tal vez se ajusta a sus necesidades.
Andy Lester

2
He estado usando Ack desde hace mucho tiempo, pero recientemente ha pasado a El buscador de plata que me parece ser más rápido el Ack
guy.gc

Creo que esta debería ser la única respuesta porque el OP dijo que quería que se hiciera con grep, pero la otra respuesta usa head (ambos funcionan, por supuesto), pero hay algunos entornos integrados / creados con herramientas mínimas donde grep es común y tail / la cabeza no lo es.
Areeb Soo Yasir

Vale la pena mencionar que agpuede ser rápido, pero no tiene la -1opción que es útil en este caso
jja

4

Puede usar el siguiente comando si desea imprimir la línea completa y el nombre del archivo si aparece una palabra en particular en el directorio actual que está buscando.

grep -m 1 -r "Not caching" * | head -1

2

Un solo revestimiento, utilizando find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit

66
Esto va a ser muy lento, ya que find generará una copia de grep por cada archivo encontrado. grep -rfunciona mucho más rápido: es la única copia que realiza recorridos de directorio.
mvp

Cierto; aunque find se puede personalizar para operar solo con resultados filtrados, lo que puede hacer que la operación sea mucho más rápida que un grep general. Depende del contexto.
Yam Marcovic
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.