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
- Relaterat (på Fråga Ubuntu ): Sök bara ett mönster / text rekursivt i det angivna filnamnet i en katalog?
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
så 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.