介绍
当在文件或目录结构中搜索文本时,Linux和类Unix系统有许多工具可以帮助你。 其中最常见的这些的是grep的 ,代表全球正则表达式打印。
使用grep,您可以轻松地搜索任何可以在任何文本输入集合中的正则表达式表达的模式。 然而,它不是最快的工具,它被创建为通用工具,没有任何类型的优化。
对于专门搜索源代码,grep的称为ACK灵感的工具被发明。 它利用Perl正则表达式高效地搜索模式的源代码,同时注意不包括不关心的结果。
在本指南中,我们将讨论如何使用ack作为超级grep替换来从源代码中挑选模式。 ack工具在可以使用Perl的任何平台上都可用,但我们将在Ubuntu 14.04服务器上演示该实用程序。
安装确认
要开始,第一步就是安装ack
你的机器上的工具。
在Ubuntu或Debian计算机上,这与从默认存储库安装实用程序一样简单。 该软件包被称为ack-grep
:
sudo apt-get update
sudo apt-get install ack-grep
由于可执行文件也已安装ack-grep
,我们可以告诉我们的系统以缩短这ack
通过键入此命令为我们的命令行工具的使用:
sudo 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意识到这不是你想要搜索的地方,所以它忽略这些目录。 这导致更集中的结果,以及更少的假阳性。
类似地,它将忽略由某些文本编辑器创建的常见备份文件。 它也不会尝试搜索通常在源目录中找到的非编码文件,例如Web文件,图像和PDF文件等的“缩小”版本。所有这些都导致几乎所有搜索的更好的结果。 您可以在执行期间始终覆盖这些设置。
应答的另一个特征是,它知道不同的语言的源文件。 您可以要求它找到目录结构中的所有Python文件。 它会返回与结尾的文件.py
,但它也将返回以行开头的任何文件:
#!/path/to/python
这将匹配其扩展名标识的文件和文件还指示使用共同的第一行调用Python解释器幻数要求 :
#!/path/to/interpreter/to/run
这创建了一种强大的方法来将非常不同种类的文件分类为相关。 您还可以根据自己的喜好添加或修改分组。
准备环境
展示ack的力量的最好方法是在源代码目录中使用它。
幸运的是,我们可以从像GitHub这样的公共网站轻松地下拉一个源代码树。 安装git,以便我们可以下拉一个仓库:
sudo apt-get install git
现在,我们需要抓一个项目。 该neovim项目就是一个很好的例子,因为它包含了许多不同类型的文件。 让我们将该存储库克隆到我们的主目录:
cd ~
git clone https://github.com/neovim/neovim.git
现在,让我们进入该目录开始:
cd neovim
查看不同的文件,了解我们的品种:
ls
BACKERS.md CMakeLists.txt Doxyfile scripts uncrustify.cfg
clint-files.txt config Makefile src vim-license.txt
clint.py contrib neovim.rb test
cmake CONTRIBUTING.md README.md third-party
就在这个顶层目录中,我们看到markdown文件,纯文本,一个Ruby文件,一个Python文件。 项目的主要部分是用C.写的。
我们也想设置一些东西,使我们的生活更容易。
我们希望通过管道输出直接进入less
,如果结果比我们的终端窗口更大。 这将防止输出不可控地从屏幕上滚动。
通过键入:
echo '--pager=less -RFX' >> ~/.ackrc
这将创建我们的ack配置文件并添加其第一个非默认选项。 我们告诉它管道输出less
了一些选项,将允许它来显示彩色输出,并智能地处理传球。
简单搜索与Ack
让我们开始吧。 首先,让我演示grep会搜索什么和ack搜索什么之间的区别。
Grep搜索目录结构中的每个文件以进行匹配。 我们可以通过键入以下内容查看此项目中的文件总数:
find . | wc -l
566
在写这篇文章的时候,在neovim项目中有566个文件。 要找出有多少那些文件,ack关心,我们可以输入:
ack -f | wc -l
497
您可以看到,我们已经删除了大约12%的文件进行搜索,甚至不做任何事情。
假设我们想要找出在这个项目中找到模式“restrict”的所有实例。 我们可以输入:
ack restrict
Doxyfile
1851:# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
1860:# code bases. Also note that the size of a graph can be further restricted by
1861:# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
vim-license.txt
3:I) There are no restrictions on distributing unmodified copies of Vim except
5: unmodified parts of Vim, likewise unrestricted except that they must
. . .
正如你所看到的,ack将“restrict”的实例划分为找到匹配的文件。 此外,它给出了确切的行号。
但是你可以看到,一些实例(我复制的所有示例部分)都是“限制”(如“受限”和“限制”)的匹配变体。 如果我们只想要“限制”一词怎么办?
我们可以使用-w
标志来告诉它搜索由字边界包围着我们的模式的实例。 这将消除这个词的其他时态:
ack -w restrict
vim-license.txt
37: add. The changes and their license must not restrict others from
clint.py
107: Specify a number 0-5 to restrict errors to certain verbosity levels.
src/nvim/fileio.c
6846: * Allow nesting of autocommands, but restrict the depth, because it's
. . .
如您所见,我们的结果现在只显示“restrict”,而没有我们之前看到的变化。 输出更集中。
您可能已经注意到,我们有不同类型的文件类型中找到的结果。 一个是纯文本文件,在Python文件中有一个文件,在C源文件中有多种情况。
如果我们想告诉ack只向我们显示在Python文件中找到的结果,我们可以通过输入:
ack -w --python restrict
clint.py
107: Specify a number 0-5 to restrict errors to certain verbosity levels.
我们没有必要指定我们正在寻找的文件模式。 我们没有必要制作特殊的正则表达式来捕获我们想要的文件类型,而不匹配其他文件。 Ack只知道许多常用语言的文件,你可以通过名称来引用它们。
我们将讨论如何修改ack为每种语言返回的文件,以及如何在以后定义自己的语言组。
分析我们的搜索焦点
我们从一个非常广泛的结果,通过添加一些非常简单的标志,只有一个。 让我们看看我们已经缩小了我们的结果。
我们可以用标志-ch
,这是我们能想到的一个简单的成语,意思是“有多少场比赛都回来了?”。 就其本身而言,该-c
标志告诉ACK只返回匹配的行数在每个文件中,就像这样:
ack -c restrict
Doxyfile:3
Makefile:0
uncrustify.cfg:0
.travis.yml:0
neovim.rb:0
vim-license.txt:5
这将为每个文件返回一行,即使没有匹配的。
该-h
本身标志禁止输出文件名前缀,并消除了零结果的文件。 在一起,他们会吐出一个单一的数字,代表搜索匹配的行数:
ack -ch restrict
101
我们从101个结果开始。 当我们告诉它注意词的边界时,我们切掉了一大块:
ack -ch -w restrict
16
当然,当我们指定我们只想查看Python文件时,我们将结果缩小为单个匹配:
ack -ch -w --python restrict
1
我们不仅缩小了我们的搜索范围,而且通过添加语言限制,我们实际上加快了搜索速度。 Ack不会简单地过滤基于您请求的语言的结果,它在搜索之前执行此操作,以免自己搜索不相关的文件。
我们可以通过定时的搜查看到这个time
的命令:
time ack -ch restrict
101
real 0m0.407s
user 0m0.363s
sys 0m0.041s
现在让我们尝试特定语言的子集搜索:
time ack -ch -w --python restrict
1
real 0m0.204s
user 0m0.175s
sys 0m0.028s
第二个明显更快。
修改搜索输出
我们已经谈到了修改搜索输出一点点,当我们过了-c
和-h
标志。 还有其他有用的标志,可以帮助我们塑造我们想要的输出。
举例来说,当你看到面前的-c
标志打印出来,其中一个匹配模式在每个文件中的行数。 我们与修改了它-h
,在此之前,但我们也可以用修改-l
来代替。 这将只返回找到匹配的文件的数字:
ack -cl restrict
Doxyfile:3
vim-license.txt:5
clint.py:1
test/unit/formatc.lua:1
src/nvim/main.c:4
src/nvim/ex_cmds.c:5
src/nvim/misc1.c:1
. . .
如您所见,以“0”结尾的所有行都已从输出中删除。
如果你想看到一个匹配在行内发现之列 ,你可以告诉ACK来打印信息,以及与--column
选项:
ack -w --column --python restrict
clint.py 107:31: Specify a number 0-5 to restrict errors to certain verbosity levels.
第二个数字是匹配的第一个字符出现的列号。 一些编辑器让你去一个特定的行和列,这使得这非常有帮助。
例如,如果你打开client.py
与文件vim
文本编辑器,你可以去比赛的确切位置键入107G
去的线,然后31|
去的列位置。 这种精确的定位可以是真正有用的,特别是如果你正在寻找一个共同的子字符串中较大的单词。
如果您需要更多的结果上下文,您可以告诉ack在匹配出现之前或之后打印出行。 例如,要在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
标志:
ack -f --python
clint.py
contrib/YouCompleteMe/ycm_extra_conf.py
我们可以做同样的事情,而且通过使用指定的文件/目录结构的模式-g
标志。 例如,我们可以通过键入以下内容来搜索在其路径中某处具有模式“log”的所有C语言文件:
ack -g log --cc
src/nvim/log.h
src/nvim/log.c
使用文件类型
我们已经看到了如何按文件类型过滤的基本知识。 我们可以告诉ack只通过键入显示C语言文件:
ack -f --cc
test/includes/pre/sys/stat.h
src/nvim/log.h
src/nvim/farsi.h
src/nvim/main.c
src/nvim/ex_cmds.c
src/nvim/os/channel.c
src/nvim/os/server.c
. . .
您可以看到ack知道的所有语言,以及通过键入以下内容与每个类别相关联的扩展和文件属性:
ack --help-types
Usage: ack-grep [OPTION]... PATTERN [FILES OR DIRECTORIES]
The following is the list of filetypes supported by ack-grep. You can
specify a file type with the --type=TYPE format, or the --TYPE
format. For example, both --type=perl and --perl work.
Note that some extensions may appear in multiple types. For example,
.pod files are both Perl and Parrot.
--[no]actionscript .as .mxml
--[no]ada .ada .adb .ads
--[no]asm .asm .s
--[no]asp .asp
. . .
正如你可以看到,这给出了每个文件类型的匹配参数。 您还可以通过在类型前添加“no”来告诉ack排除某个类别的文件。
因此,我们可以通过键入以下内容来查看C语言文件的数量:
ack -f --cc | wc -l
191
我们可以通过键入以下内容来反向查看非C语言文件的数量:
ack -f --nocc | wc -l
306
如果我们要修改类型分类怎么办? 举例来说,如果我们想要匹配.sass
, .scss
和.less
当我们正在寻找的CSS文件的文件。 我们可以看到这些已经在类型“sass”中匹配,并且键入“less”类别,但是如果我们愿意,我们也可以将它们添加到CSS类别。
为此,我们可以使用以下一般语法:
ack --type-add=TYPE:FILTER:ARGS
该--type-add
命令附加了规定的附加匹配规则TYPE
。 该FILTER
在这种情况下ext
,它通过文件扩展名指的匹配。 我们可以告诉它,我们要添加这些额外的扩展。
完整的命令如下所示:
ack --type-add=css:ext:sass,scss,less
但这仅适用于当前命令(不进行任何搜索)。 我们可以通过键入以下内容添加搜索:
ack --type-add=css:ext:sass,scss,less -f --css
这将返回在结尾的所有文件.css
, .sass
, .scss
和.less
。 在我们的项目中没有任何这些文件。 无论哪种方式,此命令不是非常有用,因为它仅存在于当前命令。 你可以将它添加到您的永久保留~/.ackrc
文件:
echo "--type-add=css:ext:sass,less" >> ~/.ackrc
如果我们想创建一个全新的类型,我们将使用--type-set
选项。 语法是完全相同的,唯一的区别是它用于定义不存在的类型。
正如你可能已经云集, TYPE
从我们最初的语法规范只是类别名称。 该FILTER
,我们看到的是文件的扩展名,但我们可以用其他过滤器为好。
我们可以通过直接匹配的文件名is
过滤器。 要创建一个名为类型example
,一个名为文件匹配example.txt
,我们可以将它添加到我们的~/.ackrc
文件:
--type-set=example:is:example.txt
我们也可以通过定义与正常的正则表达式匹配match
滤波器。 例如,如果我们想创建一个名为“bashcnf”的匹配“.bashrc”和“.bash_profile”文件的类型,我们可以键入:
echo "--type-set=bashcnf:match:/.bash(rc|_profile)/" >> ~/.ackrc
结论
如你所见,ack是一个非常灵活的工具,用于编程源代码。 即使你只是使用它来查找Linux环境中的文件,大多数时候,增加的ack的功能将是有用的。