linux最快的文本搜索神器ripgrep(grep的最好代替者)
前言
说到文本搜索工具,大家一定会知道 grep, 它是 linux 最有用并最常用的工具之一。
但如果要再一个大的工程项目中搜索某个关键词,大家也一定知道它比较耗时。
所以就有了很多替代工具,之前最出名的是 ack,ag
而最近又有了新的替代者 ripgrep, 这个工具和 ack/ag 一样都使用了多线程的方法,但 rg 比它们更快
简介
ripgrep 是一个以行为单位的搜索工具, 它根据提供的 pattern 递归地在指定的目录里搜索。它是由 rust 语言写成,相较与同类工具,它的特点就是无与伦比地快。
几个特点如下:
- 自动递归搜索 (grep 需要-r)
- 自动忽略.gitignore 中的文件以及 2 进制文件
- 可以搜索指定文件类型(rg -tpy foo限定 python 文件, rg -tjs foo排除 js 文件)
- 支持大部分 grep 的 feature(常用的都有)
- 支持各种文件编译(utf-8, utf-16, latin-1, gbk, euc-jp, shift_jis 等等)
- 支持搜索常见压缩文件(gzip, xz, lzma, bzip2, lz4)
- 自动高亮匹配的结果
- 更少的命令名称 rg (grep 是四个字符)
- 不支持多行搜索和花哨的正则
安装 ripgrep
先安装 rust
curl https://sh.rustup.rs -ssf | sh
然后一路 enter 就好了
用 rust 安装 rigpre
git clone https://github.com/burntsushi/ripgrep cd ripgrep cargo build --release cp ./target/release/rg /usr/local/bin/
最后一步根据你的情况把它放到某个在 path 里的路径里
使用
搜索结果展示
用法总体格式
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.
options | description | other |
---|---|---|
-a, --after-context <num> | 显示匹配内容后的<num>行 | 会覆盖--context |
-b, --before-context <num> | 显示匹配内容前的<num>行 | 会覆盖--context |
-b, --byte-offset | 显示匹配内容在文件中的字节偏移 | 和-o 一起使用,只打印偏移 |
-s, --case-sensitive | 大小写敏感 | 会覆盖-i(ignore case), -s(smart case) |
--color <when> | 什么时候使用颜色,默认 auto | 如果--vimgre 被使用,那么默认值是 never |
可选项有: never, auto, always, ansi | ||
--colors <color_spec>... | 设定输出颜色: | color: red, blue, green, cyan |
{type}:{attribute}:{value} |
magenta, yellow, white, black | |
{type} : path, line, column, match |
style: nobold, bold, nointense | |
{attribute} : fg, bg, style |
intense, nounderline, underline | |
{value} : a color or a text style |
example: | |
{type}:none 会清空{type}的颜色设定 |
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo | |
扩展颜色集可以被{value} 使用,如果终端支持 ansi color |
||
描述方法是'x'(256-color) 或 'x,x,x'(24-bit true color) | ||
x 是 0-255 之间的数值,默认是 10 进制, 0x 前缀是 16 进制 | ||
比如: rg --colors 'match:bg:0,128,255' | ||
或者等价的:rg --colors 'match:bg:0x0,0x80,0xff' | ||
在使用 extended color code 时 intense 和 nointense 是无效的 | ||
--column | 第一次匹配所在列数(从 1 开始) | 能够被--no-column 取消掉 |
-c, --context <num> | 显示匹配内容的前面和后面的<num>行 | 它会覆盖-b 和-a 选项 |
--context-separator <separator> | 在输出中用来分隔非连续的行 | x7f 或t 可被使用,默认是-- |
-c, --count | 只显示匹配的行数 | 如果只有一个文件给 ripgrep,那只打印匹配行数 |
可以用--with-filename 来强制打印文件名 | ||
它会覆盖--count-matches 选项 | ||
--count-matches | 只显示匹配的次数 | 可以用--with-file 来强制在只有一个文件时也输出文件名 |
--debug | 显示调试信息 | |
--dfa-size-limit <num+suffix?> | regex dfa 的上限, 默认 10m | |
-e, --encoding <encoding> | 描述文本编码, 默认是 auto | |
-f, --file <patternfile>... | 从文件中读入 pattern, 一行一 pattern | 可以被多次使用或和-e 一起组合使用,所以有组合会被匹配 |
--files | 打印所有将被搜索的文件 | 以rg <options> --files [path...] 方式使用,不能加 pattern |
-l, --files-with-matches | 只打印有匹配的文件名 | 覆盖--files-without-match |
--files-without-match | 只打印无匹配的文件名 | 覆盖 --file-with-matches |
-f, --fixed-strings | 把 pattern 当成常规文字而非 regex | 可以用--no-fixed-strings 来禁止这个选项 |
-l, --follow | 会递归搜索链接,默认关闭 | 可以用--no-follow 来关闭 |
-g, --glob <glob>... | 通配符文件或文件夹,可以用!来取反 | 可以多次使用, 会匹配.gitignore 的通配符规则 |
-h, --help | 打印帮助信息 | |
--heading | 打印文件名到匹配内容的上方而不是同一行 | 这是默认行为,可以用--no-heading 来关闭 |
--hidden | 搜索隐藏文件和文件夹 | 默认忽略, 可用--no-hidden 关闭 |
--iglob <glob>... | 同--glob, 但这个大小写不敏感 | |
-i, --ignore-case | pattern 大小写不敏感 | 可通过-s/--case-sensitive 或-s/--smart-case 覆盖这个选项 |
--ignore-file <path>... | 忽略路径,格式同.gitignore, 可多个 | 多个--ignore-file 标记时,后面优先级高 |
在命令上时,使用-g 来达到同样效果 | ||
-v, --invert-match | 反向匹配 | |
-n, --line-number | 显示文件行数,默认打开 | |
-x, --line-regexp | 只显示整行都匹配 pattern 的行 | 会覆盖--word-regexp |
-m, --max-columns <num> | 不打印长于<num>列的匹配行 | |
-m, --max-count <num> | 限制一个文件最多<num>行匹配 | |
--max-depth <num> | 限制文件夹递归搜索深度 |
rg --max-depth 0 dir/ 不执行任何搜索 |
--max-filesize <num+suffix?> | 忽略大于<num>byte 的文件 | suffix 可以是 k, m,g, 默认是 byte |
--mmap | 尽量使用 memory maps, 默认行为 | 目前它不支持所有选项, 用--no-mmap 来关闭 |
--no-config | 不读取 conf 文件, 忽略 ripgrep_config_path | |
--no-filename | 不要打印匹配文件名 | |
--no-heading | 在每个匹配行前都打印文件名 | |
--no-ignore | 取消 ignore 文件,如.gitignore, .ignore | 可以用--ignore 关闭 |
--no-ignore-global | 取消对全局的 ignore 文件读取 | 如$home/.config/git/ignore |
--no-ignore-messages | 取消解析.ignroe, .gitignore 文件相关错误 | 可通过--ignore-messages 关闭 |
--no-ignore-parent | 不读取父文件夹里的.gitignore, .ignore 文件 | 可通过 --ignore-parent 关闭 |
--no-ignore-vcs | 只全能.ignore 文件 | 可通过--ignore-vcs 关闭 |
-n, --no-line-number | 不打印匹配行数 | |
--no-messages | 不打印打开和读取文件相关错误 | |
-0, --null | 在打印的文件路径后加一个 nul 字符 | 对于 xargs 非常有用 |
-o, --only-matching | 只打印匹配的内容,而不是整行 | |
--passthru | 打印匹配和不匹配的行 | |
--path-separator <separator> | 路径分隔符,在 linux 上默认是/ | |
--pre <command> | 用<command>处理文件,并将结果给 rg | 可能有巨大的性能惩罚 |
例如 | ||
case "$1" in | ||
*.pdf) | ||
exec pdftotext "$1" - | ||
;; | ||
*) | ||
case $(file "$1") in | ||
_zstandard_) | ||
exec pzstd -cdq | ||
;; | ||
*) | ||
exec cat | ||
;; | ||
esac | ||
;; | ||
esac | ||
-p, --pretty | --color always --heading --line-number |
|
-q, --quiet | 不打印到 stdout, 如果匹配发现,停止 rg | 当 rg 用于 exit 代码时非常有用 |
--regex-size-limit <num+suffix?> | 编译 regex 的上限 | |
-e, --regexp <pattern>... | 使用正则来匹配 | 可多次使用这个选项,打印匹配任何 pattern 的行 |
可以用于搜索-开头的 pattern,如rg -e -foo
|
||
-r, --replace <replacement_text> | 用相应文件代替匹配内容打印出来 | 组序号($5)可以被使用 |
-z, --search-zip | 在 gz,bz2,xz,lzma,lz4 文件类型中搜索 | 可通过--no-search-zip 关闭 |
-s, --smart-case | 如果全小写,则大小写不敏感,否则敏感 | 可通过-s/--case-sensitive 和-i/--ignore-case 关闭 |
--sort-files | 根据文件路径排序输出结果 | 会关闭并行搜索线程 |
--stats | 打印出统计结果 | |
-a, --text | 搜索二进制文件 | 可通过--no-text 关闭 |
-j, --threads <num> | 大约使用的线程数 | |
-t, --type <type>... | 只搜索某种文件类型 | 可通过--type-lsit 来列出支持的文件类型 |
--type-add <type_spec>... | 添加文件类型 | 如rg --type-add 'foo:*.foo' -tfoo pattern
|
也可以用来创建某种包含多种文件类型的规则 | --type-add 'src:include:cpp,py,md' | |
--type-clear <type>... | 清除默认的文件类型 | |
--type-list | 列出所有内置文件类型 | |
-t, --type-not <type>... | 不要搜索某种文件类型 | |
-u, --unrestricted | -u 搜索.gitignore 里的文件, -uu 搜索隐藏文件 | -uuu 搜索二进制文件 |
-v, --version | 打印版本信息 | |
--vimgrep | 每一次匹配打印一行 | 一行有多次匹配会打印多行 |
-h, --with-filename | 打印匹配的文件路径,默认 | 可通过--no-filename 关闭 |
-w, --word-regexp | 把 pattern 作为单独单词匹配,与< >等价 |
实例展示
实例一
$ rg 'name' ./
实例二
搜索name为独立单词的内容(-w), 相当于<pattern>
$ rg -w 'name' ./
实例三
只打印包含匹配内容的文件名(-l)
$ rg -w 'name' ./ -l src/cpp/epoll_server.cpp src/cpp/uart_xtor.cpp
实例四
只搜索cpp文件(-t), 可以用-t来不搜索某种类型文件
$ rg -w 'name' ./ -tcpp
实例五
正则搜索(-e)
$ rg -e "sa.*port" ./ -tcpp
实例六
显示匹配内容及上下各两行(-c), -a/-b类似
$ rg -e "sa.*port" ./ -tcpp -c2
实例七
显示不含"debug"的行(-v)
$ rg -v "debug" -tcpp ./
实例八
只显示匹配部分(-o)
$ rg -e "if.*debug" ./ -tcpp -o
实例九
忽略大小写(-i)
$ rg -ie "if.*debug" ./ -tcpp -o
实例十
把pattern当成常量字符(-f), 像.(){}*+不需要escape,如果要搜索的字符是以-开头,那么要用--来作为分隔符,或者用rg -e "-foo"
rg -f "i++)" ./ -tcpp
实例十一
打印所有将被搜索的文件 --files
rg --files
实例十二
输出内置识别文件类型
$ 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 csharp: *.cs cshtml: *.cshtml css: *.css, *.scss csv: *.csv cython: *.pyx d: *.d dart: *.dart dhall: *.dhall docker: *dockerfile* elisp: *.el elixir: *.eex, *.ex, *.exs elm: *.elm erlang: *.erl, *.hrl fidl: *.fidl fish: *.fish fortran: *.f, *.f77, *.f90, *.f95, *.f, *.f77, *.f90, *.f95, *.pfo fsharp: *.fs, *.fsi, *.fsx gn: *.gn, *.gni go: *.go groovy: *.gradle, *.groovy gzip: *.gz h: *.h, *.hpp haskell: *.c2hs, *.cpphs, *.hs, *.hsc, *.lhs hbs: *.hbs hs: *.hs, *.lhs html: *.ejs, *.htm, *.html idris: *.idr, *.lidr java: *.java, *.jsp jinja: *.j2, *.jinja, *.jinja2 jl: *.jl js: *.js, *.jsx, *.vue json: *.json, composer.lock jsonl: *.jsonl julia: *.jl jupyter: *.ipynb, *.jpynb kotlin: *.kt, *.kts less: *.less license: *[.-]licen[cs]e*, agpl-*[0-9]*, apache-*[0-9]*, bsd-*[0-9]*, cc-by-*, copying, copying[.-]*, copyright, copyright[.-]*, eula, eula[.-]*, gfdl-*[0-9]*, gnu-*[0-9]*, gpl-*[0-9]*, lgpl-*[0-9]*, licen[cs]e, licen[cs]e[.-]*, mit-*[0-9]*, mpl-*[0-9]*, notice, notice[.-]*, ofl-*[0-9]*, patents, patents[.-]*, unlicen[cs]e, unlicen[cs]e[.-]*, agpl[.-]*, gpl[.-]*, lgpl[.-]*, licen[cs]e, licen[cs]e.* lisp: *.el, *.jl, *.lisp, *.lsp, *.sc, *.scm log: *.log lua: *.lua lz4: *.lz4 lzma: *.lzma m4: *.ac, *.m4 make: *.mak, *.mk, gnumakefile, gnumakefile, makefile, gnumakefile, makefile man: *.[0-9][cefmmpsx], *.[0-9lnpx] markdown: *.markdown, *.md, *.mdown, *.mkdn matlab: *.m md: *.markdown, *.md, *.mdown, *.mkdn mk: mkfile ml: *.ml msbuild: *.csproj, *.fsproj, *.proj, *.props, *.targets, *.vcxproj nim: *.nim nix: *.nix objc: *.h, *.m objcpp: *.h, *.mm ocaml: *.ml, *.mli, *.mll, *.mly org: *.org pdf: *.pdf perl: *.pl, *.perl, *.pl, *.plh, *.plx, *.pm, *.t php: *.php, *.php3, *.php4, *.php5, *.phtml pod: *.pod protobuf: *.proto ps: *.cdxml, *.ps1, *.ps1xml, *.psd1, *.psm1 puppet: *.erb, *.pp, *.rb purs: *.purs py: *.py qmake: *.prf, *.pri, *.pro r: *.r, *.rmd, *.rnw, *.r rdoc: *.rdoc readme: *readme, readme* rst: *.rst ruby: *.gemspec, *.rb, .irbrc, gemfile, rakefile rust: *.rs sass: *.sass, *.scss scala: *.sbt, *.scala sh: *.bash, *.bashrc, *.csh, *.cshrc, *.ksh, *.kshrc, *.sh, *.tcsh, *.zsh, .bash_login, .bash_logout, .bash_profile, .bashrc, .cshrc, .kshrc, .login, .logout, .profile, .tcshrc, .zlogin, .zlogout, .zprofile, .zshenv, .zshrc, bash_login, bash_logout, bash_profile, bashrc, profile, zlogin, zlogout, zprofile, zshenv, zshrc smarty: *.tpl sml: *.sig, *.sml soy: *.soy spark: *.spark sql: *.psql, *.sql stylus: *.styl sv: *.h, *.sv, *.svh, *.v, *.vg svg: *.svg swift: *.swift swig: *.def, *.i systemd: *.automount, *.conf, *.device, *.link, *.mount, *.path, *.scope, *.service, *.slice, *.socket, *.swap, *.target, *.timer taskpaper: *.taskpaper tcl: *.tcl tex: *.bib, *.cls, *.ltx, *.sty, *.tex textile: *.textile tf: *.tf toml: *.toml, cargo.lock ts: *.ts, *.tsx twig: *.twig txt: *.txt vala: *.vala vb: *.vb verilog: *.sv, *.svh, *.v, *.vh vhdl: *.vhd, *.vhdl vim: *.vim vimscript: *.vim webidl: *.idl, *.webidl, *.widl wiki: *.mediawiki, *.wiki xml: *.xml, *.xml.dist xz: *.xz yacc: *.y yaml: *.yaml, *.yml zsh: *.zsh, .zlogin, .zlogout, .zprofile, .zshenv, .zshrc, zlogin, zlogout, zprofile, zshenv, zshrc
总结
ripgrep的搜索速度真是快的飞起来,在浏览代码时对我的帮助非常大。我相信它对于每一个码农的价值都是无限大的,特别是结合fzf之后。
唯一的弱点是对正则的支持,但这是一个取舍,如果采用如pcre那样的库的话,一定会极大影响速度。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。