Искать только в файлах, которые соответствуют шаблону с ack


49

Может проверять поиск только по файлам, которые соответствуют определенному шаблону 'glob' (например: поиск foo во всех файлах с именем "bar * .c"). Команда

ack foo "bar*.c"

работает только в текущем каталоге.

Примечание: я знаю, что это возможно с помощью команды find -exec:

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

Но я бы хотел маленькую и простую команду ack, потому что find не пропускает каталоги контроля версий.


2
Я не понимаю, что не так с использованием find . -name "bar*.c" -exec ack foo {} \;? В этом нет ничего особенного grep, вы можете использовать любую команду с find -exec.
Terdon

1
@terdon find также просматривает каталоги контроля версий, и я не хочу этого.
compie

2
Затем отредактируйте свой вопрос и объясните ограничения, которые необходимо обойти.
Terdon

Ответы:


28

Поиск в каталогах

Основываясь на кратком описании, показанном на странице руководства, я бы сказал, что он может обрабатывать каталог, но, глядя на переключатели, он не может искать только файл, основанный на шаблоне. Для этого вам придется заручиться find. Команда ackвключает параметр, --files-from=FILEчтобы можно было получать список файлов из find.

конспект

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

использование

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

Есть --ignore-file=вариант, который может дать вам то, что вы хотите, но на самом деле кажется немного трудным для использования.

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

Поиск определенных типов файлов

Единственный другой способ, которым я могу представить, ack- это использовать его --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.

Чтобы увидеть, какие типы доступны:

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

формат. Например, оба --type = perl и --perl работают. - [нет] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx - [нет] objcpp .mm .h - [нет] perl .pl .pm .pod .t .psgi; первая строка соответствует /^#!.*\bperl/ - [нет] perltest .t

Примеры

Найдите все файлы Perl на основе имени файла (* .pm, * .pl, * .t и * .pod) и строки shebang.

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

Найдите все файлы C ++:

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

Поиск foo в баре * .c

Итак, как же вы можете достичь того, что вы хотите? Ну, вам, вероятно, придется использовать findэто:

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

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

Вы также можете использовать ackвозможность поиска файлов, которые соответствуют заданному шаблону в их именах файлов (с использованием -g <pattern>), а затем передать этот список во второй вызов ackиспользования -xили --files-from=-..

Использование -x:

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

dir1/bar1.c
1:foo
2:foo

Использование -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

В любом случае мы сопоставляем имена файлов, которые вы хотите использовать с помощью этого регулярного выражения:

\bbar.*.c$

Это соответствует файлам , чье имя bar.*cи конец после того , как с .cпомощью конца строки якоря $. Мы также стремимся убедиться, что имена имеют ограничивающий символ, используя \b. Это не удастся для файлов, которые содержат граничные символы, такие как, например, $bar.cили %bar.c.


1
Это не отвечает на мой вопрос (поиск foo во всех файлах с именем "bar * .c")
compie

1
@compie - в том смысле, что я показываю вам, как получить часть нужных вам файлов. Для поиска cppфайлов ack --type=cpp <string>. См. ackСправочную страницу для получения дополнительной информации обо всем этом. Но я в основном говорю вам, что вы не можете искать, используя ackтот путь, который хотите.
SLM

1
поэтому он отвечает в том смысле, что показывает, что он ackне может делать то, что просили.
xealits

@xealits - эта часть отвечает на это: поиск foo в баре * .c find adir -iname "bar*.c" | ack --files-from=- foo . Или, если вы просто хотите один файл:echo "barBaz.c" | ack --files-from=- foo
alexanderbird

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

14

Это легко, если тип файла известен, и ack знает много типов файлов. Так что, если, например, вы хотите искать только в файлах C, вы можете сделать:

ack --cc 'string'

Но если это не одно из известных расширений, вам нужно определить свой собственный тип. Это должно работать:

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

Обратите внимание, что вам нужны и --type-set, и --barc.

(Спасибо Энди, который также помог с этим в списке рассылки.)


1
Хорошо, это работает, но использовать find и 'ack -x' проще. Я думаю, что буду придерживаться этого.
Compie

Добавление ссылки на документы здесь было бы полезно. man ackна самом деле не помогает и не имеет, ccкогда я ищу это.
YPCrumble

ack --help = types Там есть все, что я могу придумать. Я в основном использую его для Python и Ada.
Дэвид Боштон

6

"Что нового в Ack 2?" http://beyondgrep.com/ack-2.0/

в ack 2.0 вы можете использовать новый ключ -x для передачи имен файлов из одного вызова ack в другой.

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

Только я не могу заставить его работать

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

Таким образом, кажется, -g нужно регулярное выражение, в то время как я хочу опцию стиля 'glob' ...


2
Да, -gпринимает регулярное выражение, а не шар. Вы можете написать свое регулярное выражение как .*bar.*\.c$.
Энди Лестер

2
@AndyLester Спасибо за подтверждение. Вам нравится идея «глобуса» для ack?
Compie

4

Это может показаться самым быстрым и безопасным:

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

-x Прочитать список файлов для поиска из STDIN.

Однако, если файл, скорее всего, будет в вашей locateбазе данных, это будет еще быстрее:

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

Locate также может принимать регулярные выражения старой школы, немного болезненно, но если вы ищете cфайлы, это может потребоваться. например

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

Это просто переводится как: «искать все имена файлов, оканчивающиеся на c, cpp, h, hpp или cc».


2

Ack не поддерживает выбор файла в стиле glob. Так как я действительно скучаю по этому, я создал небольшой скрипт оболочки :

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

Теперь вы можете использовать команду:

ackg foo "bar*.c"

Но обратите внимание: это, к сожалению, также будет искать в директориях контроля версий (например: .git).


2

Это можно сделать с помощью -Gопции ag, поисковика серебра (расширенный клон ack-grep).

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

Примечания:

  • agиспользует синтаксис регулярных выражений PCRE , поэтому bar.*\.cвместо bar*.c.
  • -GВариант должен предшествовать слово для поиска, как что - либо после того, что интерпретируется как имя файла.

1

Вы хотите только определенный шаблон, или вы просто хотите исходные файлы C?

Если вы хотите все файлы C, используйте

ack --cc foo

Если вы хотите, чтобы все файлы C и НЕ заголовочные файлы C использовали

ack --cc --no-hh foo

1

Ответ @chim самый лучший, но написан как комментарий, поэтому я делаю репост как официальный ответ ...

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

Мне нравится тот факт, что вы можете пересмотреть путь ...


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.