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

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

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

ack foo "bar*.c"

仅适用于当前目录。

注意:我知道 find -exec 是可能的:

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

但我想要一个小而简单的 ack 命令,因为 find 不会跳过版本控制目录。

答案1

搜索目录

根据手册页中显示的概要,我会说是的,它可以处理目录,但是查看开关,它不能仅查找基于模式的文件。为此,你必须入伍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/ --[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>),然后将此列表传递给第二次调用ackusing-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

答案2

如果文件类型已知,那就很容易了,而且 ack 知道很多文件类型。因此,例如,如果您只想在 C 文件中搜索,则可以执行以下操作:

ack --cc 'string'

但如果它不是已知的扩展之一,您需要定义自己的类型。这应该有效:

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

请注意,您需要 --type-set 和 --barc。

(感谢安迪,他也在邮件列表上提供了帮助。)

答案3

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

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

-X 读取要从 STDIN 搜索的文件列表。

但是,如果该文件可能位于您的locate数据库中,则速度会更快:

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

Locate 还可以接受老式正则表达式,有点痛苦,但如果您正在查找c文件,则可能需要它。 例如

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

这只是翻译为:“搜索所有以 c、cpp、h、hpp 或 cc 结尾的文件名。”

对于@nyxee提出了一个非常好的问题,我能看到的唯一答案是添加另一个管道:

locate --basename --regex '\.\(c\|cpp\|h\|hpp\|cc\)$' |
    grep -v '/\.'                                     |
    ack -x 'some thing'

这将跳过任何以 a 开头的目录或子目录.

答案4

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

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

我喜欢这样一个事实:你可以正则表达式路径......

相关内容