Chỉ tìm kiếm trong các tệp khớp với mẫu có ack


49

Chỉ có thể tìm kiếm ack thông qua các tệp khớp với mẫu 'toàn cầu' cụ thể (ví dụ: tìm kiếm foo trong tất cả các tệp có tên "bar * .c"). Lệnh

ack foo "bar*.c"

chỉ hoạt động trong thư mục hiện tại.

Lưu ý: Tôi biết điều đó là có thể với find -exec:

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

Nhưng tôi muốn một lệnh ack nhỏ và đơn giản, vì find không bỏ qua các thư mục kiểm soát phiên bản.


2
Tôi không hiểu, có gì sai khi sử dụng find . -name "bar*.c" -exec ack foo {} \;? Không có gì đặc biệt grep, bạn có thể sử dụng bất kỳ lệnh nào với find -exec.
terdon

1
@terdon cũng tìm kiếm thông qua các thư mục kiểm soát phiên bản và tôi không muốn điều đó.
compie

2
Sau đó, vui lòng chỉnh sửa câu hỏi của bạn và giải thích những hạn chế bạn cần phải giải quyết.
terdon

Câu trả lời:


28

Tìm kiếm thư mục

Dựa trên các bản tóm tắt được hiển thị trong trang man, tôi sẽ nói có, nó có thể xử lý một thư mục, nhưng nhìn vào các công tắc, nó không thể chỉ tìm một tệp dựa trên một mẫu. Cho rằng bạn sẽ phải tranh thủ find. Lệnh acknày bao gồm tùy chọn --files-from=FILEđể nó có thể được cung cấp một danh sách các tệp từ đó find.

tóm tắc

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

sử dụng

   --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=tùy chọn có thể cung cấp cho bạn những gì bạn muốn nhưng có vẻ hơi khó sử dụng.

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

Tìm kiếm các loại tệp cụ thể

Cách khác duy nhất tôi có thể hình dung để thực hiện điều này thông qua acklà sử dụng công --typetắc của nó :

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

Để xem những loại có sẵn:

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

định dạng. Ví dụ, cả --type = perl và --perl đều hoạt động. - [không] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx - [no] objcpp .mm .h - [no] perl .pl .pm .pod .t .psgi; phù hợp với dòng đầu tiên / ^ # #.

Ví dụ

Tìm tất cả các tệp Perl, dựa trên cả tên tệp (* .pm, * .pl, * .t và * .pod) và dòng shebang.

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

Tìm tất cả các tệp C ++:

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

Tìm kiếm foo trong thanh * .c

Vì vậy, làm thế nào bạn có thể thực hiện những gì bạn muốn? Vâng, bạn sẽ phải sử dụng findđể làm điều này:

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

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

Bạn cũng có thể sử dụng ackkhả năng tìm kiếm các tệp khớp với một mẫu nhất định trong tên tệp của họ (bằng cách sử dụng -g <pattern>), sau đó chuyển danh sách này sang lệnh thứ hai acksử dụng -xhoặc --files-from=-..

Sử dụng -x:

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

dir1/bar1.c
1:foo
2:foo

Sử dụng -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

Trong cả hai trường hợp, chúng tôi khớp với tên tệp mà bạn muốn sử dụng biểu thức chính này:

\bbar.*.c$

Điều này khớp với các tệp có tên bar.*cvà kết thúc sau khi .csử dụng kết thúc neo dòng , $. Chúng tôi cũng xem xét để đảm bảo rằng các tên có một ký tự ranh giới sử dụng \b. Điều này sẽ thất bại đối với các tệp có chứa các ký tự ranh giới như $bar.choặc %bar.cví dụ.


1
Điều này không trả lời câu hỏi của tôi (tìm kiếm foo trong tất cả các tệp có tên "bar * .c")
compie

1
@compie - theo nghĩa tôi đang chỉ cho bạn cách lấy một lát các tệp bạn muốn. Để tìm kiếm cppcác tập tin ack --type=cpp <string>. Xem acktrang của người đàn ông để biết thêm về tất cả điều này mặc dù. Nhưng điều tôi cơ bản nói với bạn là bạn không thể tìm kiếm acktheo cách bạn muốn.
slm

1
Vì vậy, nó trả lời theo nghĩa là nó cho thấy ackkhông thể làm những gì được yêu cầu.
xealits

@xealits - phần này trả lời nó: Tìm kiếm foo trong thanh * .c find adir -iname "bar*.c" | ack --files-from=- foo . Hoặc, nếu bạn chỉ muốn một tệp:echo "barBaz.c" | ack --files-from=- foo
alexanderbird

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

14

Thật dễ dàng nếu loại tệp được biết và ack biết rất nhiều loại tệp. Vì vậy, nếu, ví dụ, bạn muốn chỉ tìm kiếm trong các tệp C, hơn bạn có thể làm:

ack --cc 'string'

Nhưng nếu đó không phải là một trong những tiện ích mở rộng đã biết, bạn cần xác định loại của riêng mình. Điều này sẽ làm việc:

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

Lưu ý rằng bạn cần cả --type-set và --barc.

(Cảm ơn Andy, người cũng đã giúp với điều này trong danh sách gửi thư.)


1
Ok hoạt động nhưng sử dụng find và 'ack -x' thì đơn giản hơn. Tôi nghĩ rằng tôi sẽ gắn bó với điều đó.
compie

Thêm một liên kết đến các tài liệu ở đây sẽ hữu ích. man ackkhông thực sự giúp đỡ và không có cckhi tôi tìm kiếm nó.
YPCrumble

ack --help = các loại Có mọi thứ tôi có thể nghĩ về đó. Tôi chủ yếu sử dụng nó cho Python và Ada.
David Boshton

6

"Có gì mới trong ack 2?" http://beyondgrep.com/ack-2.0/

với ack 2.0, bạn có thể sử dụng tên tập tin -x mới để chuyển từ tên gọi ack này sang tên khác.

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

Chỉ tôi không thể làm cho nó hoạt động:

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

Vì vậy, có vẻ như -g cần một regex, trong khi tôi muốn một tùy chọn kiểu 'toàn cầu' ...


2
Vâng, -gcó một regex, không phải là một quả địa cầu. Bạn có thể viết regex của bạn như .*bar.*\.c$.
Andy Lester

2
@AndyLester Cảm ơn bạn đã xác nhận. Bạn có thích ý tưởng về tùy chọn 'global' cho ack không?
compie

3

Điều này dường như là nhanh nhất và an toàn nhất:

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

-x Đọc danh sách các tệp để tìm kiếm từ STDIN.

Tuy nhiên, nếu tệp có khả năng nằm trong locatecơ sở dữ liệu của bạn , việc này sẽ còn nhanh hơn:

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

Định vị cũng có thể chấp nhận các biểu thức chính quy của trường học cũ, hơi đau, nhưng nếu bạn đang tìm kiếm ccác tệp, nó có thể được yêu cầu. ví dụ

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

Điều đó chỉ dịch thành: "tìm kiếm tất cả tên tệp kết thúc bằng c, cpp, h, hpp hoặc cc."


2

Ack không hỗ trợ lựa chọn tập tin kiểu toàn cầu. Vì tôi thực sự nhớ điều này nên tôi đã tạo ra một kịch bản shell nhỏ ackg :

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

Bây giờ bạn có thể sử dụng lệnh:

ackg foo "bar*.c"

Nhưng lưu ý: điều này cũng không may cũng sẽ tìm kiếm trong các thư mục kiểm soát phiên bản (ví dụ: .git).


2

Điều này có thể được thực hiện với -Gtùy chọn ag, trình tìm kiếm bạc (bản sao nâng cao của ack-grep).

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

Ghi chú:

  • agsử dụng cú pháp biểu thức chính quy PCRE , vì vậy phải bar.*\.cthay thế biểu thức chính quy bar*.c.
  • Các -Gtùy chọn cần phải đứng trước các thuật ngữ tìm kiếm, như bất cứ điều gì sau đó được hiểu như là một tên tập tin.

1

Bạn chỉ muốn một mẫu nhất định, hay bạn chỉ muốn các tệp nguồn C?

Nếu bạn muốn tất cả các tệp C, sử dụng

ack --cc foo

Nếu bạn muốn tất cả các tệp C và các tệp tiêu đề KHÔNG C sử dụng

ack --cc --no-hh foo

1

Câu trả lời của @chim là tốt nhất, nhưng nó được viết dưới dạng bình luận vì vậy tôi đang đăng lại như một câu trả lời chính thức ...

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

Tôi thích thực tế là bạn có thể regex con đường ...


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.