Jag använde det här mycket, förbättringen jag försöker uppnå är att undvika ekofilnamn som inte matchade i grep. Bättre sätt att göra detta?

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

Kommentarer

Svar

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

skulle skriva ut filnamnet efter matchande rader.

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

skulle skriva ut filnamnet framför varje matchande rad (vi lägger till /dev/null för det fall där det bara finns en matchande fil som grep skriver inte ut filnamnet om den bara har skickat en fil att titta i. GNU-implementeringen av grep har ett alternativ -H för det som ett alternativ.

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

skulle bara skriva ut filnamnen på filerna som har minst en matchande rad.

Om du vill skriva ut filnamnet före matchande rader kan du använda awk istället:

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

Eller ring grep två gånger för varje fil – men att ”d skulle vara mindre effektiv eftersom det skulle köra minst ett grep -kommando och upp till två för varje fil (och läs innehållet i filen två gånger ):

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

I vilket fall som helst du vill inte slinga över utdata från find och kom ihåg att citera din variabler .

Om du vill använda en shell-loop med GNU-verktyg:

 find . -name "*.py" -exec grep -l --null something {} + | xargs -r0 sh -c " for file do printf "%s\n" "$file" grep something < "$file" done" sh  

(fungerar även på FreeBSD och derivat).

Svar

I Om du använder GNU grep kan du använda alternativet -r eller --recursive för att göra det här enkla sökandet åt dig:

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

Du behöver bara find om du behöver mer avancerade predikat.

Kommentarer

  • Beroende på versionen av GNU grep, grep kan eller kanske inte titta inuti symlänkar eller korsa symlänkar till kataloger. Du kan också hitta vissa variationer i hanteringen av andra typer av icke-vanliga filer.

Svar

Du kan berätta grep att inkludera filnamnet i utdata. Så om det finns en matchning visas den på konsolen; om det inte finns någon matchning i en fil kommer ingen rad att skrivas ut för den filen.

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

Från 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. 

Om dina filer kan ha namn med mellanslag måste du byta rör för att använda NUL-tecken som separator. Hela kommandot kommer nu att se ut så här:

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

Svar

Du kan prova något som:

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

Detta exec grep-kommando för varje fil, upptäckt av find-kommandot och dess standardfunktion för kommandot find

Svar

Använd argumentet -l.

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

En mer finsk användning skulle vara:

for file in $(find . -name "*.py" -exec grep -l something "{}" +); do echo "$file"; grep something $file; done 

Svar

Där är grep alternativ som som standard matar ut sina resultat i det format du vill ha. De två mest populära som jag känner till är ag (aka ”silver searcher”) och ack. ag annonseras som ett snabbare alternativ till 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) { ... 

Jag kan inte visa dig här, men produktionen är snyggt färgad. Jag får filnamnen i en olivgrön, linjenumren i guldgul och det matchade stycket i varje rad i blodrött. Färgerna är dock anpassningsbara.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *