Cerca solo nei file che corrispondono a un modello con ack


49

Può eseguire ricerche solo attraverso file che corrispondono a uno specifico schema "glob" (ad esempio: cerca foo in tutti i file denominati "bar * .c"). Il comando

ack foo "bar*.c"

funziona solo nella directory corrente.

Nota: so che è possibile con find -exec:

find . -name "bar*.c" -type f -exec ack foo {} + 

Ma vorrei un comando ack piccolo e semplice, perché find non salta le directory di controllo della versione.


2
Non capisco, cosa c'è di sbagliato nell'usare find . -name "bar*.c" -exec ack foo {} \;? Non c'è niente di speciale grep, puoi usare qualsiasi comando con find -exec.
terdon

1
@terdon trova anche ricerche nelle directory di controllo versione e non lo voglio.
compie

2
Quindi, modifica la domanda e spiega i limiti di cui hai bisogno per aggirare.
terdon

Risposte:


28

Ricerca nelle directory

In base alla sinossi mostrata nella pagina man direi di sì, può elaborare una directory, ma guardando gli switch non può cercare solo un file basato su un modello. Per questo dovrai arruolarti find. Il comando ackinclude l'opzione in --files-from=FILEmodo che possa essere alimentato un elenco di file da find.

sinossi

       ack [options] PATTERN [FILE...]
       ack -f [options] [DIRECTORY...]

uso

   --files-from=FILE
       The list of files to be searched is specified in FILE.  The list of
       files are separated by newlines.  If FILE is "-", the list is
       loaded from standard input.

C'è l' --ignore-file=opzione che può darti quello che vuoi, ma sembra un po 'una seccatura da usare davvero.

   --ignore-file=FILTERTYPE:FILTERARGS
       Ignore files matching FILTERTYPE:FILTERARGS.  The filters are
       specified identically to file type filters as seen in "Defining
       your own types".

Ricerca di tipi specifici di file

L'unico altro modo in cui posso concepire di fare proprio questo ackè usare il suo --typeinterruttore:

   --type=[no]TYPE
       Specify the types of files to include or exclude from a search.
       TYPE is a filetype, like perl or xml.  --type=perl can also be
       specified as --perl, and --type=noperl can be done as --noperl.

       If a file is of both type "foo" and "bar", specifying --foo and
       --nobar will exclude the file, because an exclusion takes
       precedence over an inclusion.

Per vedere quali tipi sono disponibili:

$ ack --help-types | grep -E "perl|cpp"

formato. Ad esempio, entrambi --type = perl e --perl funzionano. - [no] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx - [no] objcpp .mm .h - [no] perl .pl .pm .pod .t .psgi; la prima riga corrisponde a /^#!.*\bperl/ - [no] perltest .t

Esempi

Trova tutti i file Perl, in base sia al nome file (* .pm, * .pl, * .t e * .pod) che alla riga shebang.

$ ack -f --type perl 
examples/iwatch/iwatch/iwatch
examples/nytprof_perl/bad.pl

Trova tutti i file C ++:

$ ack -f --type=cpp
Shared/Scanner.h
Shared/Sorter.h
Shared/DicomHelper.cpp
Shared/DicomDeviationWriter.h

Ricerca foo in bar * .c

Quindi come puoi realizzare quello che vuoi? Bene, dovrai probabilmente usarlo findper fare questo:

$ find adir -iname "bar*.c" | ack --files-from=- foo
adir/bar1.c
1:foo
2:foo

adir/dir1/bar1.c
1:foo
2:foo

Puoi anche usare ackla capacità di cercare file che corrispondono a un determinato modello nei loro nomi di file (usando -g <pattern>), e quindi passare questo elenco a una seconda chiamata di ackutilizzo -xo --files-from=-..

Utilizzando -x:

$ ack -g '\bbar.*.c$' | ack -x foo
bar1.c
1:foo
2:foo

dir1/bar1.c
1:foo
2:foo

Utilizzando -files-from=-:

$ ack -g '\bbar.*.c$' | ack --files-from=- foo
bar1.c
1:foo
2:foo

dir1/bar1.c
1:foo
2:foo

In entrambi i casi stiamo abbinando i nomi dei file che desideri utilizzando questa regex:

\bbar.*.c$

Questo corrisponde a file il cui nome è bar.*ce fine dopo la .cutilizza alla fine della linea di ancoraggio, $. Cerchiamo anche di assicurarci che i nomi abbiano un carattere limite usando \b. Ciò non riuscirà per i file che contengono caratteri limite come $bar.co %bar.cad esempio.


1
Questo non risponde alla mia domanda (cerca foo in tutti i file denominati "bar * .c")
compie

1
@compie - nel senso che ti sto mostrando come ottenere una fetta dei file che desideri. Per cercare cppfile ack --type=cpp <string>. Vedi ackla pagina man per ulteriori informazioni su tutto questo però. Ma quello che ti sto sostanzialmente dicendo è che non puoi cercare usando ackil modo che desideri.
slm

1
quindi risponde nel senso che mostra che non ackpuò fare ciò che è stato chiesto.
Xealits,

@xealits: questa parte risponde: ricerca di foo in bar * .c find adir -iname "bar*.c" | ack --files-from=- foo . Oppure, se vuoi solo un file:echo "barBaz.c" | ack --files-from=- foo
alexanderbird

2
TLDR; ack -g '\bbar.*.c$' | ack -x foo
chim

14

È facile se il tipo di file è noto e ack conosce molti tipi di file. Quindi se, ad esempio, vuoi cercare solo nei file C, allora puoi fare:

ack --cc 'string'

Ma se non è una delle estensioni conosciute, devi definire il tuo tipo. Questo dovrebbe funzionare:

ack --type-set barc:match:/bar.+\.c/ --barc 'string'

Nota che hai bisogno di --type-set e --barc.

(Grazie a Andy, che ha anche aiutato con questo nella mailing list.)


1
Ok, funziona ma usare find e 'ack -x' è più semplice. Penso che rimarrò con quello.
compie il

Aggiungere un link ai documenti qui sarebbe utile. man acknon aiuta davvero e non ha ccquando lo cerco.
YPCrumble

ack --help = types C'è qualcosa a cui riesco a pensare lì. Lo uso principalmente per Python e Ada.
David Boshton,

6

"Cosa c'è di nuovo in ack 2?" http://beyondgrep.com/ack-2.0/

con ack 2.0, puoi usare il nuovo -x per reindirizzare i nomi di file da una chiamata di ack in un'altra.

ack2 -g -i filepattern | ack2 -x -w searchpattern

Solo io non riesco a farlo funzionare:

% ack -g "*bar*.c"
Invalid regex '*bar*.c':
Quantifier follows nothing in regex; marked by <-- HERE in m/* <-- HERE bar*.c/ at ack line 314.

Quindi sembra che -g abbia bisogno di una regex, mentre io voglio un'opzione di stile 'glob' ...


2
Sì, -gprende una regex, non un glob. Potresti scrivere il tuo regex come .*bar.*\.c$.
Andy Lester,

2
@AndyLester Grazie per aver confermato. Ti piace l'idea di un'opzione 'glob' per ack?
compie il

4

Questo sembrerebbe essere il più veloce e sicuro:

find . -name '*.c' | ack -x 'some string'

-x Leggi l'elenco dei file da cercare da STDIN.

Tuttavia, se è probabile che il file sia nel tuo locatedatabase, questo sarebbe ancora più veloce:

locate --basename '*.c' | ack -x 'some thing'

Locate può anche accettare espressioni regolari di vecchia scuola, un po 'dolorose, ma se stai cercando cfile, potrebbe essere necessario. per esempio

locate --basename --regexp '\.\(c\|cpp\|h\|hpp\|cc\)$' |
    ack -x 'some thing'

Questo si traduce solo in: "cerca tutti i nomi di file che terminano in c, cpp, h, hpp o cc."


2

Ack non supporta la selezione di file in stile glob. Da quando mi manca davvero questo ho creato un piccolo script shell ackg :

#!/bin/sh
# 'glob' support for ack
find -name "$2" -type f -exec ack "$1" {} +

Ora puoi usare il comando:

ackg foo "bar*.c"

Ma nota: questo sfortunatamente cercherà anche nelle directory di controllo della versione (ad es. .Git).


2

Questo può essere fatto con l' -Gopzione ag, il cercatore d'argento (un clone potenziato di ack-grep).

$ echo foo > bar_wanted.c
$ echo foo > unwanted.c
$ ag -G "bar.*\.c" foo
bar_wanted.c
1:foo

Appunti:

  • agusa la sintassi delle espressioni regolari PCRE , quindi deve essere regexp bar.*\.cinvece di bar*.c.
  • L' -Gopzione deve precedere il termine di ricerca, poiché qualsiasi cosa successiva viene interpretata come un nome file.

1

Vuoi solo un certo modello o vuoi solo file sorgente C?

Se si desidera tutti i file C., utilizzare

ack --cc foo

Se si desidera utilizzare tutti i file di intestazione C e NOT

ack --cc --no-hh foo

1

La risposta di @chim è la migliore, ma è scritta come un commento, quindi sto ripubblicando come una risposta formale ...

ack -g '\bbar.*.c$' | ack -x foo

Mi piace il fatto che tu possa ripetere il percorso ...


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.