介绍
当在文件或目录结构中搜索文本时,Linux和Unix类型的系统有许多工具可以帮助您。
使用grep,您可以轻松地搜索任何可以用任何文本输入集中的常规表达式表达的模式,但它不是最快的工具,并且它被创建为一般用途的工具,而无需任何优化。
专门用于搜索源代码,发明了一种以grep为灵感的工具,名为 ack ,它利用Perl的常规表达式有效地搜索源代码的模式,同时注意不要包括你不关心的结果。
在本指南中,我们将讨论如何使用ack作为一个超级强大的抓取替代品,从源代码中提取模式。
安装ACK
要开始,第一步是在您的机器上安装ack
工具。
在 Ubuntu 或 Debian 机器上,这就像从默认存储库中安装实用程序一样简单。
1sudo apt-get update
2sudo apt-get install ack-grep
由于可执行也被安装为ack-grep
,我们可以告诉我们的系统通过键入此命令来缩短为ack
用于我们使用该工具的命令行:
1sudo dpkg-divert --local --divert /usr/bin/ack --rename --add /usr/bin/ack-grep
现在,该工具将响应名称ack
而不是ack-grep
。
如果您计划在其他系统上使用 ack,安装方法可能会有所不同. CPAN 中的 Perl 模块称为 App::Ack
. 在其他 Linux 发行版中,存储库中的包名称可能有所不同。
Ack 关注的是什么
在我们进入 ack 的实际使用之前,让我们讨论一下它如何与grep 不同,以及 ack 领域内的文件。
该 ack 工具专门用于在程序源代码中找到文本,因此该工具已被优化以搜索某些文件并忽略其他文件。
例如,如果你正在搜索你的项目的目录结构,你几乎永远不会想要搜索版本控制系统的库层次结构. 这包含有关旧版本的文件的信息,并且可能会导致许多重复。Ack意识到这不是你想要搜索的地方,所以它忽略了这些目录。
在类似的情况下,它会忽略某些文本编辑器创建的常见备份文件,也不会尝试搜索常见的源目录中的非编码文件,如网络文件的微型
版本,图像和PDF文件等。
ack的另一个特点是它知道不同语言的源文件,你可以要求它在目录结构中找到所有Python文件,它会返回所有以「.py」结束的文件,但它也会返回任何以行开始的文件:
# !/path/to/python
这将匹配通过扩展识别的文件,以及使用常见的第一行(魔法号码呼叫)(http://en.wikipedia.org/wiki/Shebang_%28Unix%29# Magic_number)来调用Python解释器的文件:
# !/path/to/interpreter/to/run
这创建了一个强大的方式来将非常不同的类型的文件归类为相关的,您也可以添加或修改组合,以便您喜欢。
准备环境
展示 ack 的力量的最佳方法是将其用于源代码目录。
幸运的是,我们可以很容易地从GitHub这样的公共网站中拉下源树,安装 git,这样我们就可以拉下一个存储库:
1sudo apt-get install git
现在,我们需要抓住一个项目。 neovim 项目是一个很好的例子,因为它包含许多不同类型的文件。
1cd ~
2git clone https://github.com/neovim/neovim.git
现在,让我们进入该目录开始:
1cd neovim
查看不同的文件,了解我们所拥有的品种:
1ls
1BACKERS.md CMakeLists.txt Doxyfile scripts uncrustify.cfg
2clint-files.txt config Makefile src vim-license.txt
3clint.py contrib neovim.rb test
4cmake CONTRIBUTING.md README.md third-party
就在那个顶级目录中,我们看到标记文件,简单文本,Ruby文件,Python文件,而该项目的主要部分是用C写的。
我们也想设定一些事情来使我们的生活更容易。
如果结果大于我们的终端窗口,我们希望直接将输出管道变成较少
,这将防止输出无法控制地滚出屏幕。
这样做是通过打字:
1echo '--pager=less -RFX' >> ~/.ackrc
这将创建我们的 ack 配置文件,并添加其第一个非默认选项,我们告诉它将输出输出减至较少
,一些选项将允许它显示彩色输出并智能地处理通道。
使用 Ack 轻松搜索
首先,让我展示grep会搜索什么和ack搜索的区别。
Grep 搜索目录结构中的每个文件,以获取匹配。我们可以通过键入来查看该项目中的文件总数:
1find . | wc -l
1566
在此写作时,有 566 个总文件在 neovim 项目. 要找出 ack 关心的这些文件有多少,我们可以输入:
1ack -f | wc -l
1497
正如你所看到的,我们已经删除了大约12%的搜索文件,甚至没有做任何事情。
假设我们想找出这个项目中找到限制
模式的所有实例,我们可以输入:
1ack restrict
1Doxyfile
21851:# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
31860:# code bases. Also note that the size of a graph can be further restricted by
41861:# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
5
6vim-license.txt
73:I) There are no restrictions on distributing unmodified copies of Vim except
85: unmodified parts of Vim, likewise unrestricted except that they must
9. . .
正如你所看到的,ack将限制
的实例分为找到匹配的文件。
但是,正如你所看到的,一些例子(我复制的样本部分)是限制
和限制
等变异的匹配。
我们可以使用w
的旗帜来告诉它,以搜索被字边界所包围的我们模式的例子。
1ack -w restrict
1vim-license.txt
237: add. The changes and their license must not restrict others from
3
4clint.py
5107: Specify a number 0-5 to restrict errors to certain verbosity levels.
6
7src/nvim/fileio.c
86846: * Allow nesting of autocommands, but restrict the depth, because it's
9. . .
正如你所看到的,我们的结果现在只显示限制
,没有我们之前看到的变化。
您可能已经注意到,我们已经找到的结果是在不同类型的文件中找到的. 一个是简单的文本文件,有一个在Python文件中找到,并且在C源文件中有多个案例。
如果我们想告诉 ack 只向我们显示 Python 文件中发现的结果,我们可以通过键入轻松地做到这一点:
1ack -w --python restrict
1clint.py
2107: Specify a number 0-5 to restrict errors to certain verbosity levels.
我们没有需要指定我们正在寻找的文件模式,我们没有需要创建特殊的常规表达式来捕捉我们想要的文件类型而不匹配其他文件。
我们将讨论如何更改每个语言的ACK文件返回,以及如何稍后定义自己的语言组。
分析我们的搜索焦点
我们已经从一个非常广泛的结果,通过添加一些非常简单的旗帜,到只有一个,让我们看看我们已经缩小了我们的结果。
我们可以使用-ch
的旗帜,我们可以将其视为一个简单的词语,意思是有多少场合被返回?
本身,-c
的旗帜告诉ack只返回每个文件中匹配的行数,如下:
1ack -c restrict
1Doxyfile:3
2Makefile:0
3uncrustify.cfg:0
4.travis.yml:0
5neovim.rb:0
6vim-license.txt:5
这将返回每个文件的一行,即使是没有匹配的文件。
-h
旗帜本身在输出中抑制了文件名前缀,并消除了没有结果的文件,一起,它们将喷出一个单个数字,代表搜索匹配的行数:
1ack -ch restrict
1101
我们从101个结果开始,当我们告诉它要注意词界限时,我们削减了一大堆这些:
1ack -ch -w restrict
116
当然,当我们指定我们只想看到Python文件时,我们将结果缩小到一个单一的匹配:
1ack -ch -w --python restrict
11
不仅我们缩小了我们的搜索,但通过添加语言限制,我们实际上加快了搜索. Ack不仅仅是根据您所要求的语言过滤结果,它在搜索之前这样做,以免自己需要搜索无关紧要的文件。
我们可以通过使用时间
命令来定时搜索来看到这一点:
1time ack -ch restrict
1101
2
3real 0m0.407s
4user 0m0.363s
5sys 0m0.041s
现在让我们尝试语言特定的子组搜索:
1time ack -ch -w --python restrict
11
2
3real 0m0.204s
4user 0m0.175s
5sys 0m0.028s
二是显著加快。
更改搜索结果
我们已经谈到了修改搜索输出,当我们去过-c
和-h
旗帜时,有其他有用的旗帜可以帮助我们塑造我们想要的输出。
例如,正如你之前所看到的那样,c
旗打印出每个文件中发现匹配模式的行数。我们以前用h
修改了它,但我们还可以用l
修改它。
1ack -cl restrict
1Doxyfile:3
2vim-license.txt:5
3clint.py:1
4test/unit/formatc.lua:1
5src/nvim/main.c:4
6src/nvim/ex_cmds.c:5
7src/nvim/misc1.c:1
8. . .
正如你所看到的,所有以0
结束的行都从输出中被切断了。
如果你想看到 column 在一行中找到匹配,你可以告诉 ack 使用 --column
选项来打印该信息:
ack -w --column --python restrict
clint.py 107:31: Specify a number 0-5 to restrict errors to certain verbosity levels.
给出的第二个数字是相匹配的第一个字符发生的列号. 一些编辑器允许你去一个特定的行和列,这使得这非常有用。
例如,如果您使用vim
文本编辑器打开client.py
文件,您可以通过键入107G
进入行,然后进入31
进入列位置,进入匹配的准确位置。
例如,要在 python 文件中打印限制
匹配之前打印 5 行,我们可以使用-B
旗帜如下:
ack -w --python -B 5 restrict
102- output=vs7
103- By default, the output is formatted to ease emacs parsing. Visual Studio
104- compatible output (vs7) may also be used. Other formats are unsupported.
105-
106- verbose=#
107: Specify a number 0-5 to restrict errors to certain verbosity levels.
您可以指定与-A
旗帜相匹配后的背景行数:
ack -w --python -A 2 restrict
107: Specify a number 0-5 to restrict errors to certain verbosity levels.
108-
109- filter=-x,+y,...
您可以指定一般用途的语境规格,该规格会打印与-C
标志匹配的行上方和下方的一些行,例如,要在任何方向中获得3行语境,请键入:
ack -w --python -C 3 restrict
104- compatible output (vs7) may also be used. Other formats are unsupported.
105-
106- verbose=#
107: Specify a number 0-5 to restrict errors to certain verbosity levels.
108-
109- filter=-x,+y,...
110- Specify a comma-separated list of category-filters to apply: only
要只打印具有匹配的文件,而不是打印匹配本身,您可以使用-f
旗:
1ack -f --python
1clint.py
2contrib/YouCompleteMe/ycm_extra_conf.py
我们可以做同样的事情,但也可以通过使用-g
标志来指定文件 / 目录结构的模式,例如,我们可以搜索所有具有模式日志
的C语言文件,通过键入:
1ack -g log --cc
1src/nvim/log.h
2src/nvim/log.c
与文件类型合作
我们已经看到了如何按文件类型过滤的基本知识,我们可以告诉ack只通过键入向我们显示C语言文件:
1ack -f --cc
1test/includes/pre/sys/stat.h
2src/nvim/log.h
3src/nvim/farsi.h
4src/nvim/main.c
5src/nvim/ex_cmds.c
6src/nvim/os/channel.c
7src/nvim/os/server.c
8. . .
您可以通过键入查看 ack 知道的所有语言以及它与每个类别关联的扩展和文件属性:
1ack --help-types
1Usage: ack-grep [OPTION]... PATTERN [FILES OR DIRECTORIES]
2
3The following is the list of filetypes supported by ack-grep. You can
4specify a file type with the --type=TYPE format, or the --TYPE
5format. For example, both --type=perl and --perl work.
6
7Note that some extensions may appear in multiple types. For example,
8.pod files are both Perl and Parrot.
9
10 --[no]actionscript .as .mxml
11 --[no]ada .ada .adb .ads
12 --[no]asm .asm .s
13 --[no]asp .asp
14. . .
正如你可以看到的那样,这会给你每个文件类型的匹配参数,你也可以告诉ack以不
来排除某个类别的文件。
因此,我们可以通过键入来看到我们所拥有的C语言文件的数量:
1ack -f --cc | wc -l
1191
我们可以通过键入相反的方式查看非C语言文件的数量:
1ack -f --nocc | wc -l
1306
如果我们想要修改类型分类,例如,如果我们想要匹配 .sass
、 .scss
和 .less
文件,当我们正在寻找 CSS 文件时,我们可以看到这些已经在类型sass
和键入less
类别中匹配,但如果我们想要的话,我们也可以将它们添加到 CSS 类别中。
为了做到这一点,我们可以使用这个通用语法:
ack --type-add=TYPE:FILTER:ARGS
「--type-add」命令附加了特定「TYPE」的额外匹配规则。在这种情况下,「FILTER」是「ext」,意思是根据文件扩展匹配。
整个命令将是这样的:
1ack --type-add=css:ext:sass,scss,less
但是,这只适用于当前的命令(它没有进行任何搜索)。
1ack --type-add=css:ext:sass,scss,less -f --css
这将返回任何以.css
,.sass
,.scss
和.less
结束的文件,在我们的项目中不会有任何这些文件。无论如何,这个命令并不非常有用,因为它只存在于当前命令中。
1echo "--type-add=css:ext:sass,less" >> ~/.ackrc
如果我们想创建一个全新的类型,我们会使用--type-set
选项,但语法完全相同,唯一的区别是它被用来定义一个不存在的类型。
正如你可能已经收集的,我们最初的语法规格中的TYPE
只是类别名称。
我们可以直接使用is
过滤器来匹配文件名. 要创建一个名为example
的类型,以匹配名为example.txt
的文件,我们可以将此添加到我们的~/.ackrc
文件中:
1--type-set=example:is:example.txt
例如,如果我们想创建一个名为bashcnf
的类型,匹配 ".bashrc" 和 ".bash_profile" 文件,我们可以键入:
1echo "--type-set=bashcnf:match:/.bash(rc|_profile)/" >> ~/.ackrc
结论
正如你所看到的,ack 是一个非常灵活的工具,用于编程源代码的工作,即使你只是在使用它来找到你的 Linux 环境中的文件,大多数时候,ack 的增加的功率将是有用的。