Pesquise apenas em arquivos que correspondam a um padrão com ack

49

Só pode pesquisar através de arquivos que correspondam a um padrão específico de "glob" (por exemplo: procure foo em todos os arquivos denominados "bar * .c"). O comando

ack foo "bar*.c"

funciona apenas no diretório atual.

Nota: Eu sei que é possível com find -exec:

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

Mas eu gostaria de um comando ack pequeno e simples, porque find não ignora os diretórios de controle de versão.

compie
fonte
2
Eu não entendo, o que há de errado em usar find . -name "bar*.c" -exec ack foo {} \;? Não há nada de especial grep, você pode usar qualquer comando com find's -exec.
terdon
11
O @terdon find também pesquisa nos diretórios de controle de versão e eu não quero isso.
compie
2
Em seguida, edite sua pergunta e explique as limitações necessárias para solucionar o problema.
terdon

Respostas:

28

Pesquisando Diretórios

Com base na sinopse mostrada na página de manual, eu diria que sim, ele pode processar um diretório, mas, olhando para as opções, não pode procurar apenas um arquivo baseado em um padrão. Para isso você terá que se alistar find. O comando ackinclui a opção --files-from=FILEpara que ele possa receber uma lista de arquivos find.

sinopse

       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.

Existe a --ignore-file=opção que pode dar o que você quer, mas parece um pouco doloroso de usar.

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

Pesquisando Tipos Específicos de Arquivos

A única outra maneira que eu posso conceber de fazer exatamente isso acké usar seu --typeswitch:

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

Para ver quais tipos estão disponíveis:

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

formato. Por exemplo, ambos --type = perl e --perl funcionam. - [no] cpp .cpp .cc .cxx .m .hpp .hh .hxx - [no] objcpp .mm .h - [no] perl .pl .pm .pod .t .psgi; primeira linha corresponde a /^#!.*\bperl/ - [no] perltest .t

Exemplos

Encontre todos os arquivos Perl, com base no nome do arquivo (* .pm, * .pl, * .t e * .pod) e na linha shebang.

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

Encontre todos os arquivos C ++:

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

Procurando foo na barra * .c

Então, como você pode conseguir o que deseja? Bem, você provavelmente findprecisará usar isso:

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

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

Você também pode usar acka capacidade de procurar arquivos que correspondam a um determinado padrão em seus nomes de arquivos (usando -g <pattern>) e depois passar essa lista para uma segunda chamada de ackuso -xou --files-from=-..

Usando -x:

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

dir1/bar1.c
1:foo
2:foo

Usando -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

Em ambos os casos, estamos correspondendo aos nomes de arquivos que você deseja usando este regex:

\bbar.*.c$

Isso corresponde aos arquivos cujo nome é bar.*ce termina após o .cuso da âncora de fim de linha $,. Também procuramos garantir que os nomes tenham um caractere de limite usando \b. Isso falhará para arquivos que contenham caracteres de limite como $bar.cou %bar.cpor exemplo.

slm
fonte
11
Isso não respondeu à minha pergunta (procurar foo em todos os arquivos com o nome "bar * .c")
compie
11
@compie - no sentido em que estou mostrando como obter uma fatia dos arquivos que você deseja. Para procurar cpparquivos ack --type=cpp <string>. Veja acka página de manual para mais sobre tudo isso. Mas o que estou basicamente dizendo é que você não pode pesquisar ackda maneira que deseja.
Slm
11
portanto, responde no sentido em que mostra ackque não pode fazer o que foi solicitado.
xealits
@xealits - esta parte responde: Procurando foo na barra * .c find adir -iname "bar*.c" | ack --files-from=- foo . Ou, se você quiser apenas um arquivo:echo "barBaz.c" | ack --files-from=- foo
alexanderbird
2
tldr; ack -g '\bbar.*.c$' | ack -x foo
Chim
14

É fácil se o tipo de arquivo é conhecido e o ack conhece vários tipos de arquivos. Portanto, se, por exemplo, você quiser pesquisar apenas arquivos C, poderá:

ack --cc 'string'

Mas se não for uma das extensões conhecidas, você precisará definir seu próprio tipo. Isso deve funcionar:

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

Observe que você precisa de ambos --type-set e --barc.

(Obrigado a Andy, que também ajudou na lista de discussão.)

Amir E. Aharoni
fonte
11
Ok, isso funciona, mas usar find e 'ack -x' é mais simples. Eu acho que vou ficar com isso.
Compilado
Adicionar um link aos documentos aqui seria útil. man ackrealmente não ajuda e não tem ccquando eu procuro isso.
usar o seguinte comando
ack --help = types Há tudo em que consigo pensar lá. Eu o uso principalmente para Python e Ada.
David Boshton 23/02
6

"O que há de novo no ack 2?" http://beyondgrep.com/ack-2.0/

com o ack 2.0, você pode usar o novo -x para canalizar nomes de arquivos de uma chamada do ack para outra.

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

Só que não consigo fazer funcionar:

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

Assim, parece -g precisa de uma regex, enquanto eu quero uma opção de estilo 'glob' ...

compie
fonte
2
Sim, -gleva uma regex, não uma glob. Você pode escrever seu regex como .*bar.*\.c$.
Andy Lester
2
@AndyLester Obrigado por confirmar. Você gosta da ideia de uma opção "glob" para ack?
Compilado em 25/04
4

Parece ser o mais rápido e seguro:

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

-x Leia a lista de arquivos para pesquisar no STDIN.

No entanto, se é provável que o arquivo esteja no seu locatebanco de dados, isso seria ainda mais rápido:

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

O Locate também pode aceitar expressões regulares da velha escola, um pouco dolorosas, mas se você estiver procurando por carquivos, pode ser necessário. por exemplo

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

Isso apenas se traduz em: "pesquise todos os nomes de arquivos que terminam em c, cpp, h, hpp ou cc".

Orwellophile
fonte
2

O Ack não suporta a seleção de arquivos no estilo glob. Como realmente sinto falta disso, criei um pequeno script de shell ackg :

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

Agora você pode usar o comando:

ackg foo "bar*.c"

Mas observe: isso infelizmente também procurará em diretórios de controle de versão (por exemplo: .git).

compie
fonte
2

Isso pode ser feito com a -Gopção ag, o pesquisador prateado (um clone aprimorado do ack-grep).

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

Notas:

  • agusa a sintaxe da expressão regular PCRE , portanto, o regexp deve estar em bar.*\.cvez de bar*.c.
  • A -Gopção precisa preceder o termo de pesquisa, pois qualquer coisa a seguir é interpretada como um nome de arquivo.
Jon Olav Vik
fonte
1

Você deseja apenas um determinado padrão ou apenas arquivos de origem C?

Se você deseja todos os arquivos C, use

ack --cc foo

Se você deseja que todos os arquivos C e arquivos de cabeçalho NÃO C usem

ack --cc --no-hh foo
Andy Lester
fonte
1

A resposta de @chim é a melhor, mas está escrita como um comentário, por isso estou repostando como uma resposta formal ...

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

Gosto do fato de que você pode regex o caminho ...

arod
fonte