buscar y repetir nombres de archivos solo con el patrón encontrado

Respuestas:

23
find . -name '*.py' -exec grep something {} \; -print

imprimiría el nombre del archivo después de las líneas coincidentes.

find . -name '*.py' -exec grep something /dev/null {} +

imprimiría el nombre del archivo delante de cada línea coincidente (agregamos /dev/nullpara el caso donde solo hay un archivo coincidente, ya grepque no imprime el nombre del archivo si se pasa solo un archivo para buscar. La implementación de GNU greptiene una -Hopción para eso como alternativa).

find . -name '*.py' -exec grep -l something {} +

imprimiría solo los nombres de los archivos que tienen al menos una línea coincidente.

Para imprimir el nombre del archivo antes de las líneas coincidentes, puede usar awk en su lugar:

find . -name '*.py' -exec awk '
  FNR == 1 {filename_printed = 0}
  /something/ {
    if (!filename_printed) {
      print FILENAME
      filename_printed = 1
    }
    print
  }' {} +

O llame grepdos veces para cada archivo, aunque eso sería menos eficiente ya que ejecutaría al menos un grepcomando y hasta dos para cada archivo (y leería el contenido del archivo dos veces):

find . -name '*.py' -exec grep -l something {} \; \
                    -exec grep something {} \;

En cualquier caso, no desea recorrer la salida de findese tipo y recordar citar sus variables .

Si desea utilizar un bucle de shell, con herramientas GNU:

find . -name '*.py' -exec grep -l --null something {} + |
   xargs -r0 sh -c '
     for file do
       printf "%s\n" "$file"
       grep something < "$file"
     done' sh

(también funciona en FreeBSD y derivados).

Stéphane Chazelas
fuente
6

Si estás usando GNU grep, puede utilizar su -ro --recursivela opción de hacer este sencillo hallazgo para usted:

grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match

Solo necesita findsi necesita predicados más avanzados.

Toby Speight
fuente
1
Dependiendo de la versión de GNU grep, greppuede o no mirar dentro de enlaces simbólicos o enlaces simbólicos transversales a directorios. También puede encontrar algunas variaciones en el manejo de otros tipos de archivos no regulares.
Stéphane Chazelas
5

Puede decirle a grep que incluya el nombre del archivo en la salida. Entonces, si hay una coincidencia, se mostrará en la consola; Si no hay coincidencia dentro de un archivo, no se imprimirá ninguna línea para ese archivo.

find . -name "*.py" | xargs grep -n -H something

De la man grep:

-H       Always print filename headers with output lines
-n, --line-number
         Each output line is preceded by its relative line number in the file, starting at line 1.  The line number counter is reset for each file processed.
         This option is ignored if -c, -L, -l, or -q is specified.

Si sus archivos pueden tener nombres con espacios en ellos, debe cambiar la tubería para usar caracteres NUL como separador. El comando completo ahora se verá así:

find . -name "*.py" -print0 | xargs -0 grep -n -H something
rollstuhlfahrer
fuente
1

Puedes probar algo como:

find . -name "*.py:" -exec grep -l {} \;

Este comando exec grep para cada archivo, descubierto por el comando find y su función estándar de comando find

Romeo Ninov
fuente
1

Usa el -largumento.

for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done

Un uso más difícil sería:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
kmkaplan
fuente
1

Hay grepalternativas que, de forma predeterminada, generan sus resultados en el formato que desee. Los 2 la mayoría de los populares, que yo sepa son ag(también conocido como "el buscador de plata") y ack. agse anuncia como una alternativa más rápida a ack.

$ ag '^\w+\s*\w+\(' ~/build/i3/src
build/i3/src/display_version.c
58:void display_running_version(void) {

build/i3/src/load_layout.c
42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
518:json_content_t json_determine_content(const char *filename) {
575:void tree_append_json(Con *con, const char *filename, char **errormsg) {

build/i3/src/x.c
64:CIRCLEQ_HEAD(state_head, con_state) state_head =
67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head =
97:void x_con_init(Con *con, uint16_t depth) {
...

No puedo mostrarte aquí, pero la salida está perfectamente coloreada. Obtengo los nombres de archivo en un verde oliva, los números de línea en amarillo dorado y la pieza coincidente en cada línea en rojo sangre. Sin embargo, los colores son personalizables.

JoL
fuente