Шукайте лише у файлах, які відповідають шаблону з ack


49

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

ack foo "bar*.c"

працює лише в поточному каталозі.

Примітка. Я знаю, що це можливо за допомогою find -exec:

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

Але я хотів би невелику і просту команду ack, оскільки пошук не пропускає каталоги управління версіями.


2
Я не розумію, що не так з використанням find . -name "bar*.c" -exec ack foo {} \;? У цьому немає нічого особливого grep, ви можете використовувати будь-яку команду з find -exec.
terdon

1
@terdon також шукає пошук у каталогах управління версіями, і я цього не хочу.
compie

2
Потім відредагуйте своє запитання та поясніть обмеження, з якими вам потрібно подолати.
terdon

Відповіді:


28

Пошук каталогів

На основі конспекту, показаного на сторінці man, я б сказав, що так, він може обробляти каталог, але, дивлячись на комутатори, він не може шукати лише файл на основі шаблону. Для цього вам доведеться заручитися 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 - [no] objcpp .mm .h - [no] 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
шим

14

Це легко, якщо тип файлу відомий, а Ack знає багато типів файлів. Отже, якщо, наприклад, ви хочете шукати лише у файлах C, тоді ви можете:

ack --cc 'string'

Але якщо це не одне з відомих розширень, вам потрібно визначити власний тип. Це має працювати:

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

Зауважте, що вам потрібні і - type-set, і --barc.

(Дякую Енді, який також допоміг із цим у списку розсилки.)


1
Добре, що працює, але використовувати find і 'ack -x' простіше. Я думаю, я буду дотримуватися цього.
композиція

Додавання посилання на документи тут було б корисним. man ackнасправді не допомагає і не має, ccколи я це шукаю.
YPCrumble

ack --help = види Там все, що я можу придумати. Я в основному використовую його для Python та Ada.
Девід Боштон

6

"Що нового в акку 2?" http://beyondgrep.com/ack-2.0/

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

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?
композиція

3

Це здавалося б найшвидшим і безпечним:

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

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

Однак, якщо файл, можливо, знаходиться у вашій locateбазі даних, це буде ще швидше:

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

Знайти також може приймати старі шкільні регулярні вирази, трохи болісно, ​​але якщо ви шукаєте cфайли, це може знадобитися. напр

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

Це просто перекладається з: "пошук усіх імен файлів, які закінчуються на c, cpp, h, hpp або cc."


2

Ack не підтримує вибір файлів у глобальному стилі. Оскільки я дуже сумую за цим, я створив невеликий скрипт оболонки ackg :

#!/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.