Buscar archivos de forma recursiva por contenido

Buscar archivos de forma recursiva por contenido

Quiero buscar archivos de forma recursiva en mi árbol de origen por contenido. Intenté lo siguiente usando grep:

$ grep -rn printf | grep %s | grep bcm_errmsg\(rv\)

Esto me devuelve cada línea como quería, pero ahora me gustaría obtener el nombre de cada archivo que coincida, así que lo cambié a:

$ grep -rn printf | grep %s | grep -l bcm_errmsg\(rv\)

pero en lugar de imprimir los nombres de los archivos, solo obtengo

(standard input)

impreso en salida estándar. ¿Cómo soluciono esto para obtener cada nombre de archivo y ruta (para usarlos sed)?

Lo que quiero hacer: buscar cada archivo con printflíneas que también contengan %sy bcm_errmsg(rv)luego aplicar el siguiente comando sed a los archivos encontrados:

sed -i 's/%s/%d/g; s/bcm_errmsg(rv)/rv/g;'

Respuesta1

Creo que estás complicando demasiado las cosas. Para buscar cadenas fooen todos los archivos ubicados en el directorio y subdirectorios actuales, simplemente ejecute

grep -r "foo" *

De forma predeterminada, grep genera la línea coincidente precedida por el nombre del archivo donde se encontró.

En cambio, lo siguiente solo generará el nombre del archivo, sin la línea coincidente:

grep -rl "foo" *

Respuesta2

Siguiendo la idea inicial de @steeldriver, puedes hacer:

egrep -rl '.*printf.*%s.*bcm_errmsg\(rv\).*' . | xargs -d '\n' sed -i '/printf/ s/%s/%d/; /printf/ s/bcm_errmsg(rv)/rv/'

Respuesta3

grep -rlZP '(?=.*printf)(?=.*%s)(?=.*bcm_errstr\(rv\))' . |
xargs -r0 sed -i -e '
        /%s/!b
        /printf/!b
        /bcm_errstr(rv)/!b
        s/%s/%d/g;s/bcm_errstr(rv)/rv/g
'

Primero ejecutamos un directorio recursivo. desde el directorio actual que busca archivos que tengan las cadenas: printf, %s y bcm_errstr(rv) en la misma línea pero tal vez en cualquier orden. Las grepopciones que nos ayudan a lograrlo son:

  • -r=> se iniciará recursivamente en todos los archivos en el directorio actual y debajo.
  • -l=> enumerará los nombres de archivos que coincidan con los criterios, es decir, las 3 cadenas en la misma línea.
  • -Z=> los nombres de archivos seleccionados están separados por nulos (\0) en lugar de la nueva línea habitual (\n) para que podamos abordar cualquier tipo de nombres de archivos.
  • -P=> habilite el motor de expresiones regulares de Perl mediante el cual podemos usar búsquedas anticipadas para determinar si las 3 cadenas existen en la misma línea.

Al otro lado de la tubería, xargsestá esperando recibir los nombres de los archivos, separados por \0. Luego envía todos estos nombres de archivos, tanto como sea posible, a la línea de comando sed. El comando sed que ya conoces de tu pregunta anterior, donde realiza los subs. solo en aquellas líneas que contienen las 3 cadenas en la misma línea.

información relacionada