Jak rekurencyjnie grepować pierwsze 50 wierszy każdego pliku w katalogu?

10

Muszę przeszukać pierwsze 50 wierszy każdego pliku w katalogu i jego podkatalogach.

Spowoduje to wykonanie części rekurencyjnej, ale jak ograniczyć się tylko do pierwszych 50 wierszy każdego pliku?

grep -r "matching string here" .

Niektóre z tych plików są ogromne i chcę je dopasowywać tylko w pierwszych 50 wierszach. Próbuję przyspieszyć ten proces, nie wyszukując megabajtów danych binarnych w niektórych plikach.

zevlag
źródło
czy chcesz po prostu znać pasujące pliki, czy chcesz mieć tylko pasujący ciąg, czy też pasujący ciąg wraz z nazwą pliku?
gniourf_gniourf

Odpowiedzi:

11
  • Jeśli chcesz tylko pasujących plików:

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

    lub

    find . -type f -exec bash -c 'grep -q "matching string here" < <(head -n 50 "$1") && printf '%s\n' "$1"' _ {} \;
    
  • Jeśli chcesz tylko pasujące ciągi:

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

    albo lepiej,

    find . -type f -exec head -q -n 50 {} + | grep "matching string here"
    
  • A jeśli chcesz obu:

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

Uwagi

  • Może być nieco łatwiejsze z sedzamiast kombinacji head- grep.
  • Chciałbym podkreślić, że wszystkie trzy metody są w 100% bezpieczne w odniesieniu do nazw plików, które mogą zawierać zabawne symbole (spacje, znaki nowej linii itp.).
  • W dwóch z tych metod zakładam, że masz całkiem nową wersję bash.
  • Możesz użyć -exec ... +każdej metody, ale wtedy będziesz musiał samodzielnie kodować swoją wewnętrzną pętlę! (trywialne ćwiczenie pozostawione czytelnikowi). Może to być nieco bardziej wydajne, jeśli masz pliki gazillion.
gniourf_gniourf
źródło
4

Jeśli potrzebujesz wyjścia grep jak w oryginale, możesz:

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

Jeśli potrzebujesz tylko nazw plików, możesz zamienić drugi grep na echo "$f".

Michael Suelmann
źródło
1

Musisz połączyć kilka różnych narzędzi, aby uzyskać pożądaną funkcjonalność. Użyj findpolecenia, aby ponownie wyszukać katalogi, znaleźć wszystkie pliki i wykonać headpolecenie dla każdego znalezionego pliku. headKomenda może być użyta do zrzutu tylko pierwsze 50 linii każdego pliku. Na koniec potokuj wyjście do grep, aby wyszukać żądany ciąg.

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

Sierść psa
źródło