¿Cómo grep las primeras 50 líneas de cada archivo en un directorio de forma recursiva?

10

Necesito buscar las primeras 50 líneas de cada archivo en un directorio y sus subdirectorios.

Esto hará la parte recursiva, pero ¿cómo limito solo las primeras 50 líneas de cada archivo?

grep -r "matching string here" .

Algunos de estos archivos son enormes, y solo quiero que coincidan en las primeras 50 líneas. Estoy tratando de acelerar el proceso al no buscar megabytes de datos binarios en algunos archivos.

zevlag
fuente
¿Desea conocer los archivos que coinciden, o desea tener solo la cadena coincidente o desea la cadena coincidente junto con el nombre del archivo?
gniourf_gniourf

Respuestas:

11
  • Si solo quieres los archivos que coinciden:

    find . -type f -exec bash -c 'grep -q "matching string here" < <(head -n 50 "$1")' _ {} \; -printf '%p\n'
    

    o

    find . -type f -exec bash -c 'grep -q "matching string here" < <(head -n 50 "$1") && printf '%s\n' "$1"' _ {} \;
    
  • Si solo desea las cadenas coincidentes:

    find . -type f -exec head -n 50 {} \; | grep "matching string here"
    

    o mejor,

    find . -type f -exec head -q -n 50 {} + | grep "matching string here"
    
  • Y si quieres ambos:

    find . -type f -exec bash -c 'mapfile -t a < <(head -n 50 "$1" | grep "matching string here"); printf "$1: %s\n" "${a[@]}"' _ {} \;
    

Observaciones

  • Podría ser un poco más fácil en sedlugar del combo head- grep.
  • Permítanme enfatizar que los tres métodos son 100% seguros con respecto a los nombres de archivos que pueden contener símbolos divertidos (espacios, líneas nuevas, etc.).
  • En dos de estos métodos, supongo que tiene una versión decentemente reciente de bash.
  • Podrías usar -exec ... +cada método, ¡pero luego tendrás que codificar tu ciclo interno tú mismo! (ejercicio trivial dejado al lector). Esto podría ser un poco más eficiente si tiene millones de archivos.
gniourf_gniourf
fuente
4

Si necesita la salida grep como en el original, puede hacer:

find . -type f | while read f; do 
  if head -n 50 "$f"|grep -s "matching string here"; then
    grep "matching string here" "$f" /dev/null 
  fi
done

Si solo necesita los nombres de archivo, puede reemplazar el segundo grep con echo "$f".

Michael Suelmann
fuente
1

Tendrá que combinar algunas utilidades diferentes para obtener la funcionalidad deseada. Use el findcomando para repetir los directorios, encontrar todos los archivos y ejecutar el headcomando en cada archivo encontrado. El headcomando se puede usar para volcar solo las primeras 50 líneas de cada archivo. Finalmente, canalice la salida a grep para buscar la cadena deseada.

find . -type f -exec head -n 50 {} ";" | grep "matching string here"

Pelo del perro
fuente