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

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

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *