Szukaj tylko w plikach pasujących do wzorca z potwierdzeniem

49

Może przeszukiwać tylko pliki pasujące do określonego wzorca „glob” (np. Wyszukaj foo we wszystkich plikach o nazwie „bar * .c”). Komenda

ack foo "bar*.c"

działa tylko w bieżącym katalogu.

Uwaga: Wiem, że jest to możliwe dzięki find -exec:

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

Ale chciałbym małe i proste polecenie ack, ponieważ find nie pomija katalogów kontroli wersji.

współdziałać
źródło
2
Nie rozumiem, co jest złego w korzystaniu find . -name "bar*.c" -exec ack foo {} \;? Nie ma w tym nic specjalnego grep, możesz użyć dowolnego polecenia z find's -exec.
terdon
1
@terdon find przeszukuje również katalogi kontroli wersji i nie chcę tego.
konkurs
2
Następnie edytuj pytanie i wyjaśnij ograniczenia, które musisz obejść.
terdon

Odpowiedzi:

28

Wyszukiwanie katalogów

Na podstawie streszczenia pokazanego na stronie podręcznika powiedziałbym, że tak, może przetworzyć katalog, ale patrząc na przełączniki, nie może poszukać tylko pliku opartego na wzorcu. W tym celu musisz się zaciągnąć find. Polecenie ackzawiera opcję, --files-from=FILEdzięki czemu można podać listę plików z find.

streszczenie

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

stosowanie

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

Istnieje --ignore-file=opcja, która może dać ci to, czego chcesz, ale wydaje się trochę trudna w użyciu.

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

Wyszukiwanie określonych typów plików

Jedynym innym sposobem, w jaki mogę to zrobić, ackjest użycie jego --typeprzełącznika:

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

Aby zobaczyć, jakie typy są dostępne:

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

format. Na przykład działają zarówno --type = perl, jak i --perl. - [no] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx - [no] objcpp .mm .h - [no] perl .pl .pm .pod .t .psgi; dopasowanie do pierwszego wiersza /^#!.*\bperl/ - [no] perltest .t

Przykłady

Znajdź wszystkie pliki Perla na podstawie nazwy pliku (* .pm, * .pl, * .t i * .pod) oraz linii shebang.

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

Znajdź wszystkie pliki C ++:

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

Wyszukiwanie foo w barze * .c

Więc jak możesz osiągnąć to, czego chcesz? Cóż, prawdopodobnie będziesz musiał findto zrobić:

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

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

Możesz także skorzystać ackze zdolności wyszukiwania plików, które pasują do danego wzorca w nazwach plików (using -g <pattern>), a następnie przekaż tę listę do drugiego wywołania ackusing -xlub --files-from=-

Używanie -x:

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

dir1/bar1.c
1:foo
2:foo

Używanie -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

W obu przypadkach dopasowujemy nazwy plików, których chcesz użyć za pomocą tego wyrażenia regularnego:

\bbar.*.c$

Dopasowuje pliki, których nazwa jest bar.*ci koniec po .cużyciu końcu linii kotwicy $. Staramy się również upewnić, że nazwy mają znak graniczny przy użyciu \b. Nie powiedzie się to dla plików zawierających znaki graniczne, takie jak $bar.club %bar.cna przykład.

slm
źródło
1
To nie odpowiada na moje pytanie (szukaj foo we wszystkich plikach o nazwie „bar * .c”)
compie
1
@compie - robi to w tym sensie, że pokazuję ci, jak uzyskać kawałek pożądanych plików. Aby wyszukać cpppliki ack --type=cpp <string>. Więcej ackinformacji na ten temat można znaleźć na stronie podręcznika użytkownika. Ale w zasadzie mówię ci, że nie możesz wyszukiwać ackw sposób, w jaki chcesz.
slm
1
więc odpowiada w tym sensie, że pokazuje, że nie ackmoże zrobić tego, o co został poproszony.
xealits,
@xealits - ta część odpowiada na to: Wyszukiwanie foo w barze * .c find adir -iname "bar*.c" | ack --files-from=- foo . Lub, jeśli chcesz tylko jeden plik:echo "barBaz.c" | ack --files-from=- foo
alexanderbird
2
tldr; ack -g '\bbar.*.c$' | ack -x foo
chim
14

Łatwo jest, jeśli typ pliku jest znany, a ack zna wiele typów plików. Jeśli na przykład chcesz wyszukiwać tylko w plikach C, możesz:

ack --cc 'string'

Ale jeśli nie jest to jedno ze znanych rozszerzeń, musisz zdefiniować własny typ. To powinno działać:

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

Pamiętaj, że potrzebujesz zarówno --type-set, jak i --barc.

(Dzięki Andy, który również pomógł w tym na liście mailingowej).

Amir E. Aharoni
źródło
1
Ok, to działa, ale użycie find i 'ack -x' jest prostsze. Myślę, że się z tym trzymam.
konkurować
Pomocne byłoby dodanie linku do dokumentów tutaj. man acktak naprawdę nie pomaga i nie ma, cckiedy tego szukam.
YPCrumble 16.04.16
ack --help = types Jest tam coś, o czym mogę myśleć. Używam go głównie do Pythona i Ady.
David Boshton
6

„Co nowego w ack 2?” http://beyondgrep.com/ack-2.0/

z ack 2.0 możesz użyć nowego -x do potokowania nazw plików z jednego wywołania ack do drugiego.

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

Tylko że nie mogę go uruchomić:

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

Wydaje się więc, że -g potrzebuje wyrażenia regularnego, a ja chcę opcję stylu globalnego ...

współdziałać
źródło
2
Tak, -gwymaga wyrażenia regularnego, a nie globalnego. Możesz napisać swoje wyrażenie regularne jako .*bar.*\.c$.
Andy Lester
2
@AndyLester Dziękujemy za potwierdzenie. Czy podoba Ci się pomysł „globalnej” opcji potwierdzenia?
konkurs
3

Wydawałoby się to najszybszym i najbezpieczniejszym:

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

-x Przeczytaj listę plików do wyszukiwania ze STDIN.

Jeśli jednak plik prawdopodobnie znajduje się w locatebazie danych, byłoby to jeszcze szybsze:

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

Locate może również przyjmować wyrażenia regularne ze starej szkoły, co jest nieco bolesne, ale jeśli szukasz cplików, może być konieczne. na przykład

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

To po prostu przekłada się na: „wyszukaj całą nazwę pliku, która kończy się na c, cpp, h, hpp lub cc”.

Orwellophile
źródło
2

Ack nie obsługuje wyboru plików w stylu globalnym. Ponieważ naprawdę mi tego brakuje, stworzyłem mały skrypt powłoki shellg :

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

Teraz możesz użyć polecenia:

ackg foo "bar*.c"

Ale uwaga: to niestety przeszuka także katalog kontroli wersji (np. .Git).

współdziałać
źródło
2

Można to zrobić za pomocą -Gopcji ag, srebrnego wyszukiwarki (ulepszony klon ack-grep).

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

Uwagi:

  • agużywa składni wyrażeń regularnych PCRE , więc wyrażenie regularne musi być bar.*\.czamiast bar*.c.
  • Ta -Gopcja musi poprzedzać wyszukiwane hasło, ponieważ wszystko później interpretowane jest jako nazwa pliku.
Jon Olav Vik
źródło
1

Czy chcesz tylko określony wzorzec, czy tylko pliki źródłowe w C?

Jeśli chcesz wszystkie pliki C., użyj

ack --cc foo

Jeśli chcesz używać wszystkich plików C i NIE plików nagłówka C.

ack --cc --no-hh foo
Andy Lester
źródło
1

Odpowiedź @chim jest najlepsza, ale jest napisana jako komentarz, więc przesyłam jako oficjalną odpowiedź ...

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

Podoba mi się to, że możesz regexować ścieżkę ...

arod
źródło