Często z tego korzystałem, ulepszenie, które próbuję osiągnąć, polega na unikaniu echa nazw plików, które nie pasują do grep. Lepszy sposób na zrobienie tego?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Komentarze
- Podobne (na Zapytaj Ubuntu ): Rekursywne wyszukiwanie wzorca / tekstu tylko w określonej nazwie pliku katalogu?
Odpowiedź
find . -name "*.py" -exec grep something {} \; -print
wypisuje nazwę pliku po pasujących wierszach.
find . -name "*.py" -exec grep something /dev/null {} +
wypisze nazwę pliku przed każdym pasującym wierszem (dodajemy /dev/null
w przypadku, gdy jest tylko jeden pasujący plik jako grep
nie drukuje nazwy pliku, jeśli przekazano tylko jeden plik do przeszukania. Implementacja GNU grep
ma alternatywną opcję -H
).
find . -name "*.py" -exec grep -l something {} +
wypisze tylko nazwy plików, które mają przynajmniej jedną pasującą linię.
Aby wydrukować nazwę pliku przed pasującymi wierszami, możesz użyć awk zamiast tego:
find . -name "*.py" -exec awk " FNR == 1 {filename_printed = 0} /something/ { if (!filename_printed) { print FILENAME filename_printed = 1 } print }" {} +
Lub zadzwoń pod numer grep
dwa razy dla każdego pliku – chociaż to „d będzie mniej wydajne, ponieważ uruchomiłoby co najmniej jedno polecenie grep
i maksymalnie dwa dla każdego pliku (i dwukrotnie odczytaj zawartość pliku ):
find . -name "*.py" -exec grep -l something {} \; \ -exec grep something {} \;
W każdym przypadku nie chcesz zapętlać wyników find
w ten sposób i pamiętaj o zacytowaniu 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).
Odpowiedź
I Jeśli używasz programu GNU grep, możesz użyć jego opcji -r
lub --recursive
, 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 find
, jeśli potrzebujesz bardziej zaawansowane predykaty.
Komentarze
- W zależności od wersji GNU
grep
,grep
może, ale nie musi, zaglądać do dowiązań symbolicznych lub przechodzić przez dowiązania symboliczne do katalogów. Możesz także zauważyć pewne różnice w obsłudze innych typów niestandardowych plików.
Odpowiedź
Ty może nakazać grep, aby dołączył nazwę pliku do wyniku. Więc jeśli jest dopasowanie, zostanie wyświetlone na konsoli; jeśli w pliku nie ma dopasowania, dla tego pliku nie zostanie wydrukowana żadna linia.
find . -name "*.py" | xargs grep -n -H something
From the 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 zmienić potok, aby użyć znaków NUL jako separatora. Pełne polecenie będzie teraz wyglądać następująco:
find . -name "*.py" -print0 | xargs -0 grep -n -H something
Odpowiedź
Możesz spróbuj czegoś takiego:
find . -name "*.py:" -exec grep -l {} \;
To polecenie exec grep dla każdego pliku, odkryte przez polecenie find i jego standardową funkcję polecenia wyszukiwania
Odpowiedź
Użyj argumentu -l
.
for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done
Bardziej wyszukane użycie byłoby:
for file in $(find . -name "*.py" -exec grep -l something "{}" +); do echo "$file"; grep something $file; done
Odpowiedź
Tam są grep
alternatywami, które domyślnie wyświetlają wyniki w żądanym formacie. Dwa najpopularniejsze, które znam, to ag
(a.k.a. „poszukiwacz srebra”) i ack
. ag
jest 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 wynik jest starannie pokolorowany. Nazwy plików otrzymuję w kolorze oliwkowym, numery wierszy w kolorze złotożółtym, a pasujący fragment w każdym wierszu w kolorze krwistoczerwonym. Kolory można jednak dostosować.