只能通过与特定“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>
),然后将此列表传递给第二次调用ack
using-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
我喜欢这样一个事实:你可以正则表达式路径......