znajdź i powtórz nazwy plików tylko ze znalezionym wzorcem

Odpowiedzi:

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

wypisze nazwę pliku po pasujących wierszach.

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

wypisuje nazwę pliku przed każdą pasującą linią (dodajemy /dev/nullw przypadku, gdy istnieje tylko jeden pasujący plik, ponieważ grepnie wypisuje nazwy pliku, jeśli zostanie przekazany tylko jeden plik do sprawdzenia. Implementacja GNU grepma taką -Hopcję jako alternatywa).

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

wypisuje tylko nazwy plików, które mają co najmniej jedną pasującą linię.

Aby wydrukować nazwę pliku przed pasującymi liniami, możesz zamiast tego użyć awk:

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

Lub zadzwoń grepdwukrotnie dla każdego pliku - choć byłoby to mniej wydajne, ponieważ uruchomiłoby co najmniej jedno greppolecenie i maksymalnie dwa dla każdego pliku (i przeczytałby zawartość pliku dwa razy):

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

W każdym razie nie chcesz zapętlać wyników findtakich działań i pamiętaj, aby cytować swoje zmienne .

Jeśli chcesz użyć pętli powłoki z narzędziami 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

(działa również na FreeBSD i pochodnych).

Stéphane Chazelas
źródło
6

Jeśli używasz GNU grep, możesz użyć jego -rlub --recursiveopcji, aby wykonać to proste wyszukiwanie:

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

Potrzebujesz tylko findwtedy, gdy potrzebujesz bardziej zaawansowanych predykatów.

Toby Speight
źródło
1
W zależności od wersji GNU grep, grepmoże lub nie może zajrzeć do wnętrza dowiązania lub dowiązania Ruch do katalogów. Możesz również znaleźć pewne różnice w obsłudze innych typów plików nieregularnych.
Stéphane Chazelas
5

Możesz powiedzieć grepowi, aby uwzględnił nazwę pliku na wyjściu. Jeśli więc istnieje dopasowanie, zostanie wyświetlone na konsoli; jeśli w pliku nie ma zgodności, dla tego pliku nie zostanie wydrukowana żadna linia.

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

Z 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.

Jeśli twoje pliki mogą mieć nazwy ze spacjami, musisz przełączyć potok, aby używać znaków NUL jako separatora. Pełna komenda będzie teraz wyglądać następująco:

find . -name "*.py" -print0 | xargs -0 grep -n -H something
rollstuhlfahrer
źródło
1

Możesz spróbować czegoś takiego:

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

To polecenie exec grep dla każdego pliku odkrytego przez polecenie find i jego standardowa funkcja polecenia find

Romeo Ninov
źródło
1

Użyj -largumentu.

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

Bardziej wyszukanym zastosowaniem byłoby:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
kmkaplan
źródło
1

Istnieją grepalternatywy, które domyślnie wyświetlają wyniki w żądanym formacie. Dwa najbardziej popularne, które znam to ag(znany również jako „srebrny poszukiwacz”) i ack. agjest reklamowany jako szybsza alternatywa dla 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) {
...

Nie mogę cię tutaj pokazać, ale wydruk jest starannie kolorowy. Dostaję nazwy plików w kolorze oliwkowo-zielonym, numery linii w kolorze złotożółtym, a dopasowany kawałek w każdej linii w kolorze krwistoczerwonym. Kolory można jednak dostosowywać.

JoL
źródło