Procura apenas em arquivos que correspondem a um padrão com ack

41

Pode procurar apenas por arquivos que correspondam a um padrão específico de 'glob' (por exemplo: procure por foo em todos os arquivos chamados "bar * .c"). O comando

ack foo "bar*.c"

só funciona no diretório atual.

Nota: Eu sei que é possível encontrar -exec:

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

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

    
por compie 24.04.2014 / 12:37

8 respostas

23

Pesquisando diretórios

Com base na sinopse mostrada na página man, eu diria que sim, ele pode processar um diretório, mas, olhando para os switches, ele não pode procurar apenas um arquivo baseado em um padrão. Para isso, você precisará inscrever find . O comando ack inclui a opção --files-from=FILE para que possa ser alimentada com uma lista de arquivos de 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 opção --ignore-file= que pode dar o que você quer, mas parece um pouco difícil 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 posso conceber de fazer exatamente isso via ack é usar sua opção --type :

   --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.     - [não] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx     - [não] objcpp .mm .h     - [no] perl .pl .pm .pod .t .psgi; primeira linha corresponde /^#!.*\bperl/     - [não] 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 por foo na barra * .c

Então, como você pode conseguir o que quer? Bem, você provavelmente terá que usar find para fazer 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 a capacidade de ack de pesquisar arquivos que correspondam a um determinado padrão em seus nomes de arquivos (usando -g <pattern> ) e passar essa lista para uma segunda chamada de ack usando -x ou --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 combinando os nomes de arquivos que você deseja usando este regex:

\bbar.*.c$

Corresponde aos arquivos cujo nome é bar.*c e termina após .c usando a âncora de fim de linha, $ . Também procuramos garantir que os nomes tenham um caractere de limite usando \b . Isso falhará nos arquivos que contêm caracteres de limite, como $bar.c ou %bar.c , por exemplo.

    
por 24.04.2014 / 14:39
13

É fácil se o tipo de arquivo for conhecido, e o ack conhece muitos tipos de arquivos. Então, se, por exemplo, você quiser pesquisar somente em arquivos C, você pode fazer:

ack --cc 'string'

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

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

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

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

    
por 24.04.2014 / 17:19
6

"O que há de novo no ack 2?" link

with ack 2.0, you can use the new -x to pipe filenames from one invocation of ack into another.

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

Só não consigo trabalhar:

% 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 um regex, enquanto eu quero uma opção de estilo 'glob' ...

    
por 24.04.2014 / 16:29
2

O Ack não suporta a seleção de arquivos no estilo glob. Como eu 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 note: isto infelizmente também irá procurar em dirs de controle de versão (por exemplo: .git).

    
por 19.12.2014 / 11:37
1

Você quer apenas um determinado padrão, ou você quer apenas arquivos-fonte C?

Se você quiser todos os arquivos C, use

ack --cc foo

Se você quiser que todos os arquivos C e arquivos de cabeçalho NOT C usem

ack --cc --no-hh foo
    
por 24.04.2014 / 16:36
1

Isso pode ser feito com a opção -G para ag, o pesquisador de prata (um clone aprimorado de ack-grep) .

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

Notas:

  • ag usa a sintaxe de expressão regular PCRE , portanto o regexp deve ser bar.*\.c em vez de bar*.c .
  • A opção -G precisa preceder o termo de pesquisa, já que qualquer coisa depois disso é interpretada como um nome de arquivo.
por 05.08.2015 / 08:27
1

Isso parece ser o mais rápido e seguro:

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

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

No entanto, se o arquivo estiver no banco de dados locate , isso será ainda mais rápido:

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

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

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

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

    
por 06.10.2016 / 13:00
0

Usando o zsh, você pode fazer:

ls **/a*.txt | ack --files-from=- something
    
por 23.04.2015 / 18:16

Tags