文本搜索 Ripgrep

原文链接

Ripgrep 是命令行下一个基于行的搜索工具,RipGrep 使用 Rust 开发,可以在多平台下运行,支持 Mac、Linux 和 Windows 等平台。RipGrep 与 The Silver Searcher、Ack 和 GNU Grep 的功能类似。

RipGrep 官方号称比其它类似工具在搜索速度上快上 N 倍,VSCode 也从 1.11 版本开始默认将 RipGrep 做为其搜索工具,由此其功能强大可见一斑。

项目地址:https://github.com/BurntSushi/ripgrep

Ripgrep 支持的一些特性

  • 自动递归搜索 (grep 需要 -R)。

  • 自动忽略 .gitignore 中的文件以及二进制文件和隐藏文件。

  • 可以搜索指定文件类型,如:rg -tpy foo 则限定只搜索 Python 文件,rg -Tjs foo 则排除掉 JS 文件。

  • 支持大部分 Grep 的 特性,例如:显示搜索结果的上下文、支持多个模式搜索、高亮匹配的搜索结果以及支持 Unicode 等。

  • 支持各种文本编码格式,如:UTF-8、UTF-16、latin-1、GBK、EUC-JP、Shift_JIS 等。

  • 支持搜索常见格式的压缩文件,如:gzip、xz、lzma、bzip2、lz4 等。

  • 自动高亮匹配的结果。

Ripgrep 官方性能基准测试结果

  • 搜索整个 Linux 内核源代码

  • 在单个大文件上对 Ripgrep 和 GNU Grep 进行比较,文件大小大约 9.3G。

Ripgrep 效果图

安装 Ripgrep

Ripgrep 具有良好跨平台特性,支持在 Linux、macOS、Windows 等多种平台下安装。官方也提供了各平台对应的二进制版本,下面我们以 Linux 平台为例使用二进制版本进行安装。

$ wget  https://github.com/BurntSushi/ripgrep/releases/download/0.10.0/ripgrep-0.10.0-x86_64-unknown-linux-musl.tar.gz $ tar xzvf ripgrep-0.10.0-x86_64-unknown-linux-musl.tar.gz $ cp ripgrep-0.10.0-x86_64-unknown-linux-musl/rg  /usr/local/bin/

如果你使用其它平台,方法与其类似。你可根据实际情况在官方下载页面下载对应版本进行安装。当然官方也提供了其它多种多样的安装方式,具体可参考官方安装文档。

Ripgrep 语法格式

USAGE:    rg [OPTIONS] PATTERN [PATH ...]    rg [OPTIONS] [-e PATTERN ...] [-f PATTERNFILE ...] [PATH ...]    rg [OPTIONS] --files [PATH ...]    rg [OPTIONS] --type-list    command | rg [OPTIONS] PATTERN ARGS:    <PATTERN>            A regular expression used for searching. To match a pattern beginning with a            dash, use the -e/--regexp flag.            For example, to search for the literal '-foo', you can use this flag:                rg -e -foo            You can also use the special '--' delimiter to indicate that no more flags            will be provided. Namely, the following is equivalent to the above:                rg -- -foo    <PATH>...            A file or directory to search. Directories are searched recursively. Paths specified on            the command line override glob and ignore rules.
  • 支持的命令行选项

这里我们把一些常用选项做下介绍。

更多命令行选项,可通过 rg --help 自行查看。

Ripgrep 使用实例

搜索指定文件中包含关键字的内容

$ rg 'github.com'  README.md 1:<h1 align="center"><a title="New «NexT» 6.0.0 version [Reloaded]" href="https://github.com/theme-next/hexo-theme-next">NexT</a></h1>
6:[![mnt-image]](https://github.com/theme-next/hexo-theme-next)
21:More NexT examples [here](https://github.com/iissnan/hexo-theme-next/issues/119). 41:   $ curl -s https://api.github.com/repos/iissnan/hexo-theme-next/releases/latest | grep tarball_url | cut -d '"' -f 4 | wget -i - -O- | tar -zx -C themes/next --strip-components=1 51:   $ curl -L https://api.github.com/repos/iissnan/hexo-theme-next/tarball/v5.1.2 | tar -zxv -C themes/next --strip-components=1 57:   $ git clone --branch v5.1.2 https://github.com/iissnan/hexo-theme-next themes/next 67:   $ curl -L https://api.github.com/repos/iissnan/hexo-theme-next/tarball | tar -zxv -C themes/next --strip-components=1 73:   $ git clone https://github.com/iissnan/hexo-theme-next themes/next 110:For those who also encounter **Error: Cannot find module 'hexo-util'** [issue](https://github.com/iissnan/hexo-theme-next/issues/1490), please check your NPM version. 128:282:NexT uses [Tomorrow Theme](https://github.com/chriskempson/tomorrow-theme) with 5 themes for you to choose from. 288:Head over to [Tomorrow Theme](https://github.com/chriskempson/tomorrow-theme) for more details. 367:[download-latest-url]: https://github.com/iissnan/hexo-theme-next/archive/master.zip 368:[releases-latest-url]: https://github.com/iissnan/hexo-theme-next/releases/latest 369:[releases-url]: https://github.com/iissnan/hexo-theme-next/releases 370:[tags-url]: https://github.com/iissnan/hexo-theme-next/tags 371:[commits-url]: https://github.com/iissnan/hexo-theme-next/commits/master

搜索指定文件中包含以关键字开头的单词的内容

$ rg 'lang\w+' README.md 154:168:Default language is English. 171:language: en 172:173:174:175:176:177:178:179:180:181:

搜索指定文件中包含以关键字开头的内容

$ rg 'hexo\w*' README.md 1:<h1 align="center"><a title="New «NexT» 6.0.0 version [Reloaded]" href="https://github.com/theme-next/hexo-theme-next">NexT</a></h1>
3:<p align="center">NexT is a high quality elegant <a href="http://hexo.io">Hexo</a> theme. It is crafted from scratch, with love.</p>
6:[![mnt-image]](https://github.com/theme-next/hexo-theme-next)
9:[![hexo-image]][hexo-url]
21:More NexT examples [here](https://github.com/iissnan/hexo-theme-next/issues/119). 25:**1.** Change dir to **hexo root** directory. There must be `node_modules`, `source`, `themes` and other directories: 27:   $ cd hexo 41:   $ curl -s https://api.github.com/repos/iissnan/hexo-theme-next/releases/latest | grep tarball_url | cut -d '"' -f 4 | wget -i - -O- | tar -zx -C themes/next --strip-components=1 51:   $ curl -L https://api.github.com/repos/iissnan/hexo-theme-next/tarball/v5.1.2 | tar -zxv -C themes/next --strip-components=1 57:   $ git clone --branch v5.1.2 https://github.com/iissnan/hexo-theme-next themes/next

搜索指定目录及子目中包含关键字的内容

$ rg 'github.com' ./ ./src/scrollspy.js 6:* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)./src/affix.js 6: * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)./src/js.cookie.js 3: * https://github.com/js-cookie/js-cookie

搜索以关键字为独立单词的内容

$ rg -w 'github.com' ./ ./bower.json 36:    "url" : "http://github.com/julianshapiro/velocity.git"./velocity.ui.js 58:        var abortError = "Velocity UI Pack: You need to update Velocity (jquery.velocity.js) to a newer version. Visit http://github.com/julianshapiro/velocity.";./velocity.js 442:    /* IE detection. Gist: https://gist.github.com/julianshapiro/9098609 */ 463:    /* rAF shim. Gist: https://gist.github.com/julianshapiro/9497513 */ 472:            /* Technique by Erik Moller. MIT license: https://gist.github.com/paulirish/1579671 */ 480:    /* Array compacting. Copyright Lo-Dash. MIT License: https://github.com/lodash/lodash/blob/master/LICENSE.txt */ 522:        /* Copyright Martin Bohm. MIT License: https://gist.github.com/Tomalak/818a78a226a0738eaade */

搜索包含关键字内容的文件并且只打印文件名

$ rg -w 'github.com' ./ -l ./velocity.js ./bower.json ./velocity.ui.js ./velocity.ui.min.js

在指定文件类型格式为 JS 的文件中搜索包含关键字的内容

RipGrep 实现的方式存在多种多样,这里介绍比较常用的两种。

$ rg 'function writeOnCanvas' --type js source/lib/Han/dist/han.js 1726:function writeOnCanvas( text, font ) {
  • 第二种:使用 --glob 选项来通配需要的文件类型。

$ rg  'function writeOnCanvas' -g '*.js'
source/lib/Han/dist/han.js 1726:function writeOnCanvas( text, font ) {

如果要同时搜索多个文件类型可以写成下面这样。

$ rg 'Hanzi' -g '*.{js,css}'
han.min.js 2:/*! Han.css: the CSS typography framework optimised for Hanzi */ han.js 3: * Han.css: the CSS typography framework optimised for Hanzi 48:  // Address Hanzi and Western script mixed spacing 426:    /* Hanzi and Western mixed spacing han.css 4:/*! Han.css: the CSS typography framework optimised for Hanzi */ han.min.css 4:/*! Han.css: the CSS typography framework optimised for Hanzi */

在当前目下并且不包含文件类型格式为 CSS 的文件中搜索包含关键字的内容

$ rg 'revertVowel' --type-not css source/lib/Han/dist/han.min.js(this["comb-liga-zhuyin"]=O.substZhuyinCombLiga
(this.context)),this},revertVowelCombLiga:function(){try{this["comb-liga-vowel"].revert("all")}catch(a){}return this},revertVowelICombLiga:function(){try{this["comb-liga-vowel-i"].revert("all")}catch(a){}return this},revertZhuyinCombLiga:function(){try{this["comb-liga-zhuyin"].revert("all")}catch(a){}return this},revertCombLigaWithPUA:function(){try{this["comb-liga-vowel"].revert("all"),this["comb-liga-vowel-i"].revert("all"),this["comb-liga-zhuyin"].revert("all")}catch(a){}return this},substInaccurateChar:function(){return this["inaccurate-char"]=O.substInaccurateChar(this.context),this},revertInaccurateChar:function(){try{this["inaccurate-char"].revert("all")}catch(a){}return this}}),a.addEventListener("DOMContentLoaded",function(){var a;K.classList.contains("han-init")?O.init():(a=J.querySelector(".han-init-context"))&&(O.init=O(a).render())}),("undefined"==typeof b||b===!1)&&(a.Han=O),O});source/lib/Han/dist/han.js 2939:  revertVowelCombLiga: function() {
2946:  revertVowelICombLiga: function() {

你也可以用下面的更简洁的写法来达到同样的效果。

$ rg 'revertVowel' -Tcss

使用正则表达式进行关键字搜索

$ rg -e "noConf.*lict" ./ ./js.cookie.js 21:     api.noConflict = function () {./scrollspy.js 166:  $.fn.scrollspy.noConflict = function () {./affix.js 139:  $.fn.affix.noConflict = function () {

搜索匹配关键字的内容及显示其上下内容各两行

$  rg -e "noConf.*lict"  -C2 js.cookie.js 19-     var OldCookies = window.Cookies;
20-     var api = window.Cookies = factory();
21:     api.noConflict = function () {
22-         window.Cookies = OldCookies;
23-         return api;scrollspy.js 164-  // =====================
165- 166:  $.fn.scrollspy.noConflict = function () {
167-    $.fn.scrollspy = old 168-    return this affix.js 137-  // =================
138- 139:  $.fn.affix.noConflict = function () {
140-    $.fn.affix = old 141-    return this

搜索不包含关键字的内容

$ rg -v "hexo" merge-configs.js 2: 3:var merge = require('./merge');
4: 5:/** 8: */ 12:    if ( data && data.next ) {
13:      if ( data.next.override ) {
15:      } else {
17:      }
18:    }
19:  }
20:});
21: 30:});

搜索关键字并只显示关键字部分的内容

$ rg -e "hexo.*warn" -o ./ ./tags/lazy-image.js 12:hexo.log.warn ./merge-configs.js 23:hexo.log.warn 24:hexo.log.warn 25:hexo.log.warn 26:hexo.log.warn 27:hexo.log.warn 28:hexo.log.warn 29:hexo.log.warn ./tags/button.js 13:hexo.log.warn ./tags/full-image.js 12:hexo.log.warn

搜索关键字并忽略关键字大小写的内容

$ rg -ie "Return.*" merge.js 103:var root = freeGlobal || freeSelf || Function('return this')(); 120:    return freeProcess && freeProcess.binding('util'); 134: * @returns {Object} Returns `map`. 137:  // Don't return `map.set` because it's not chainable in IE 11. 139:  return map; 148: * @returns {Object} Returns `set`. 151:  // Don't return `set.add` because it's not chainable in IE 11.

把关键字当成常量字符进行搜索

关键字中包含 .(){}*+ 类似字符时,不需要手动转义。

$ rg -F "i++)" ./ ./tags/exturl.js 27:  for (; i < len; i++) {./tags/group-pictures.js 795:    for (var i = 0; i < rows; i++) {
805:    for (var i = 0; i < rows.length; i++) {
825:    for (var i = 0; i < pictures.length; i++) {

如果要搜索的字符是以 - 开头时,要用 -- 来作为分隔符。

$ rg -- -1 merge.js 190:  var index = -1, 210:  var index = -1, 233:  var index = -1, 255:  var index = -1, 317:  var index = -1, 348:  var index = -1, 435:  var index = -1, 533:  var index = -1, 605:  return assocIndexOf(this.__data__, key) > -1; 645:  var index = -1, 889: * @returns {number} Returns the index of the matched value, else `-1`. 898:  return -1;

或者使用 -e 参数也可以达到类似目的。

$ rg -e "-1" source/js source/js/src/js.cookie.js 113:                    cookie = cookie.slice(1, -1);
155:                expires: -1 source/js/src/motion.js 190:    cursor: -1, 223:        getMistLineSettings($logoLineBottom, '-100%')

打印当前目下所有将被搜索的文件列表

$ rg --files merge.js merge-configs.js tags/lazy-image.js tags/center-quote.js tags/tabs.js tags/note.js tags/button.js tags/full-image.js tags/group-pictures.js tags/label.js tags/exturl.js

输出所有内置可识别文件类型

$ rg --type-list agda: *.agda, *.lagda aidl: *.aidl amake: *.bp, *.mk asciidoc: *.adoc, *.asc, *.asciidoc asm: *.S, *.asm, *.s ats: *.ats, *.dats, *.hats, *.sats avro: *.avdl, *.avpr, *.avsc awk: *.awk bazel: *.bzl, BUILD, WORKSPACE bitbake: *.bb, *.bbappend, *.bbclass, *.conf, *.inc bzip2: *.bz2 c: *.H, *.c, *.cats, *.h cabal: *.cabal cbor: *.cbor ceylon: *.ceylon clojure: *.clj, *.cljc, *.cljs, *.cljx cmake: *.cmake, CMakeLists.txt coffeescript: *.coffee config: *.cfg, *.conf, *.config, *.ini cpp: *.C, *.H, *.cc, *.cpp, *.cxx, *.h, *.hh, *.hpp, *.hxx, *.inl creole: *.creole crystal: *.cr, Projectfile cs: *.cs ......

自定义搜索文件类型

默认情况下,Ripgrep 附带了一堆预定义的类型。 通常,这些类型对应于众所周知的公共格式。 您也可以定义自己的类型,例如:您可能经常搜索 Web 类型文件,其中包含 Javascript、HTML 和 CSS 类型的文件。

$ rg --type-add 'web:*.html' --type-add 'web:*.css' --type-add 'web:*.js' -tweb display han.css 28:  display: block; 34:  display: inline-block; 37:  display: none; 45:  display: none; 174:  display: table; /* 1 */ han.js 442:    // The feature displays the following characters 446:    'display-as': { 1732:  canvas.style.display = 'none'

也可以直接简写成

$ rg --type-add 'web:*.{html,css,js}' -tweb display

不过有一点是要注意的,上面增加的 Web 类型文件是临时的,只对当前命令有效。如果需要长期使用自定义的类型,你可以新增一个别名来在每次运行 RipGrep 时自动增加对应的文件类型。

$ alias rg="rg --type-add 'web:*.{html,css,js}'"

当然还有另一种方法来达到类似的目的,那就是使用 RipGrep 的配置文件,RipGrep 的配置文件默认为 $HOME/.ripgreprc

$ cat $HOME/.ripgreprc
--max-columns=150--type-add web:*.{html,css,js}*--glob=!git/*--glob
!git/*--colors=line:none --colors=line:style:bold--smart-case

将包含关键字的内容在查找结果中进行替换

RipGrep 提供了一个在查找过程中直接将关键字内容进行替换的功能,下面我们来看一个将关键字中部分内容的小写字母转大写字母的例子。

$ rg browse README.md --replace Browse 305:322:![Browser-image]
324:[![Browser Stack](.github/Browserstack_logo.png)](https://www.Browserstack.com/)
325:>**BrowserStack** is a cloud-based cross-Browser testing tool that enables developers to test their websites across various Browsers on different operating systems and mobile devices, without requiring users to install virtual machines, devices or emulators. 343:[Browser-image]: https://img.shields.io/badge/Browser-%20chrome%20%7C%20firefox%20%7C%20opera%20%7C%20safari%20%7C%20ie%20%3E%3D%209-lightgrey.svg 344:[Browser-url]: https://www.Browserstack.com

上面的结果实质上只是在标准输出中进行替换,并不会对实际文件进行修改。如果你需要对实际文件进行修改,你可以结合 Sed 命令来达到目的。

  • 如果你使用 GNU Sed (CentOS、Ubuntu 等各种 Linux 发行版),可以使用以下命令。

$ rg browse --files-with-matches | xargs sed -i 's/browse/Browse/g'
  • 如果您使用 BSD Sed( macOS 和 FreeBSD),则必须将以上命令修改为以下命令。

$ rg browse --files-with-matches | xargs sed -i '' 's/browse/Browse/g'

BSD Sed 中的 -i 标志需要提供文件扩展名以对所有已修改的文件进行备份,这里指定空字符串可防止进行文件备份。

  • 如果您的文件路径中包含空格,则需要使用 NUL 终结符分隔文件路径。这里就需要使用 -0 参数来告诉 Ripgrep 在每个路径之间输出 NUL 字节,并告诉 Xargs 读取由 NUL 字节分隔的路径。

$ rg Browse --files-with-matches -0 | xargs -0 sed -i '' 's/Browse/browse/g'

直接在压缩文件中搜索包含关键字的内容

Ripgrep 目前仅支持 gzip、bzip2、lzma、lz4 和 xz 这几种压缩格式,并且需要在系统上已安装相应的 gzip,bzip2 和 xz 工具包。也就是说,Ripgrep 是通过 Shelling 到另一个进程来进行解压缩的。

$ rg -z license UNLICENSE.gz 24:For more information, please refer to <http://unlicense.org/>

Ripgrep 目前不会搜索存档格式,因此会跳过 *.tar.gz 文件。

自动补全功能

RipGrep 提供的二进制包中默认提供了 SHELL 自动补全功能,只需根据不同 SHELL 放到对应目录即可使用了。

  • Bash

$ mv rg.bash $XDG_CONFIG_HOME/bash_completion/ 或者 $ mv rg.bash /etc/bash_completion.d/
$ mv _rg $fpath/
$ mv rg.fish $HOME/.config/fish/completions/

参考文档

http://www.google.com http://t.cn/ROI5tMv http://t.cn/Rs3caWW http://t.cn/Rs3F6Ty

最后更新于