仅在与ack模式匹配的文件中搜索


49

只能确认通过匹配特定“ glob”模式的文件进行搜索(例如:在名为“ bar * .c”的所有文件中搜索foo)。命令

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 2014年

2
然后,请编辑您的问题并解释您需要解决的限制。
terdon

Answers:


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都可以工作。-[no] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx-[no] objcpp .mm .h-[no] perl .pl .pm .pod .t .psgi; 第一行匹配/^#!.*\bperl/-[no] perltest .t

例子

根据文件名(* .pm,*。pl,*。t和* .pod)和shebang行查找所有Perl文件。

$ 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

在bar * .c中搜索foo

那么,您如何才能完成自己想要的?好吧,您将不得不使用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
这不能回答我的问题(在名为“ bar * .c”的所有文件中搜索foo)
compie 2014年

1
@compie-从某种意义上讲,这是在向您展示如何获取所需文件的一部分。搜索cpp文件ack --type=cpp <string>。有关ack所有这些的更多信息,请参见的手册页。但是,我基本上要告诉您的是,您无法使用ack所需的方式进行搜索。
slm

1
因此它确实回答了它表示ack无法完成所要求的事情。
xealits 2014年

@xealits-此部分回答它:在bar * .c中搜索foo 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。

(感谢Andy,他也在邮件列表中提供了帮助。)


1
可以,但是使用find和'ack -x'比较简单。我想我会坚持下去。
compie

在此处添加文档链接将很有帮助。man ack搜索并没有真正的帮助,也没有帮助cc
YPCrumble '16

ack --help = types我可以想到的一切。我主要将其用于Python和Ada。
David Boshton '17

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$
Andy Lester 2014年

2
@AndyLester感谢您的确认。您是否喜欢ack的“全局”选项的想法?
compie

3

这似乎是最快和最安全的:

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不支持选择全局样式文件。因为我真的很想念这个,所以我创建了一个小的shell脚本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正则表达式语法,因此regexp必须bar.*\.cbar*.c
  • -G选项需要在搜索词之前,因为之后的任何内容都被解释为文件名。

1

您是否只需要某种模式,还是只需要C源文件?

如果要所有C文件,请使用

ack --cc foo

如果要使用所有C文件而不是C头文件

ack --cc --no-hh foo

1

@chim的答案是最好的,但是它是作为评论写的,所以我要重新发布为正式答案...

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

我喜欢您可以重新定义路径的事实。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.