Ripgrep: grep・ag・Git grep などより高速な検索ツール(2016年)
(blog.burntsushi.net)- ripgrep(
rg) は、The Silver Searcher流のコード検索の使いやすさと GNU grep級の生の性能を組み合わせた Rust製コマンドライン検索ツールで、Linux・Mac・Windows向けバイナリを提供する - 25件のベンチマークでは、単一の大きなファイル検索と大規模ディレクトリ検索の両方において、性能・正確性の面で
ripgrepを明確に上回るツールはなく、Unicode対応のコストも小さく抑えられている .gitignoreの処理、隠しファイル・バイナリファイルのデフォルト除外、ファイルタイプフィルタ、任意の PCRE2 サポート、複数エンコーディングや圧縮ファイルの検索、前処理フィルタまで含み、コード検索ツールの実用範囲を広げている- Linuxカーネルリポジトリと OpenSubtitles2016 実験の差は、リテラル最適化、Teddy SIMD 多重パターン検索、Aho-Corasick、UTF-8 デコード方式、行カウント、
.gitignore処理コストに大きく左右される - 多数の小さなファイルを並列検索する場合、メモリマップは遅くなることがあり、単一の大きなファイルでは有利なことがあるため、
ripgrepは状況に応じて中間バッファ検索とメモリマップ検索を使い分ける
ripgrepが目指した位置
ripgrepは、コード検索ツールの使いやすさとgrep系ツールの性能の両立を狙ったコマンドライン検索ツールである- 比較対象は
GNU grep、git grep、The Silver Searcher(ag)、Universal Code Grep(ucg)、The Platinum Searcher(pt)、siftである - ベンチマークで確認しようとした要点は3つである
- 単一ファイルと大規模ディレクトリ検索の両方で、
ripgrepを明確に上回るツールはない - Unicode対応を適切に提供しつつ、大きな性能コストを要求しない
- 複数ファイルを一度に検索する場合、メモリマップは概して高速になるというより、むしろ遅くなることがある
- 単一ファイルと大規模ディレクトリ検索の両方で、
- 著者は
ripgrepとその基盤となる正規表現エンジンの開発者であり、ベンチマークが選別されてバイアスを含む可能性があることを明らかにしている
機能と基本動作
ripgrepの実行ファイル名はrgである- デフォルトの検索は現在のディレクトリを再帰的に探索し、
.gitignoreを尊重し、隠しファイルとバイナリファイルをスキップする .rgignoreにも対応し、.rgignoreのパターンは.gitignoreより優先される-u、-uu、-uuuで ignore ファイルの無視、隠しファイルの包含、バイナリファイルの包含へと範囲を広げられるrg -uuuはgrep -a -rに近い
- ファイルタイプフィルタに対応する
rg -tpy foo: Pythonファイルのみ検索rg -Tjs foo: JavaScriptファイルを除外--type-addで新しいファイルタイプ規則を追加可能
grepの多くの機能も提供する- コンテキスト出力
- 複数パターン検索
- 色付きハイライト
- 完全な Unicode 対応
- デフォルトの正規表現エンジンは look-around と backreference をサポートしないが、
-Pで PCRE2 エンジンを選択すればこれらの機能を利用できる - 一部の UTF-16 自動検出と、
-E/--encodingに基づくエンコーディング指定にも対応する- UTF-16、latin-1、GBK、EUC-JP、Shift_JIS などを含む
-z/--search-zipにより、gzip、xz、lzma、bzip2、lz4 などの圧縮ファイル検索をサポートする- PDFテキスト抽出、追加の展開、復号、自動エンコーディング検出などの任意の前処理フィルタにも対応する
使わない理由
- 可搬性とどこでも使えることを最優先するなら、標準準拠で広くインストールされている grep が適している
- 他のツールにある特定の機能やバグに依存している場合、
ripgrepは適さない可能性がある - 一部の性能上のエッジケースでは、他のツールのほうがうまく動作する場合がある
- インストールできない、またはプラットフォームが対応していない場合も利用できない
grep系ツールの動作構造
- 検索ツールは大きく3段階を経る
- 検索対象ファイルの収集
- 実際の検索
- 結果の出力
grep系ツールは大きなファイルをうまく検索する必要があるため、正規表現エンジンの性能が重要であるack系ツールは、再帰ディレクトリ探索と.gitignoreのような ignore 規則の適用を高速に処理する必要があるripgrepは2つのアプローチを組み合わせようとしている- 高速な正規表現エンジン
- 並列検索
- 検索対象のフィルタリング
ファイル収集と ignore 処理
ack系ツールでは、現在のディレクトリでどのファイルを検索するかを高速に決定することが重要である- ディレクトリ走査の性能は、不要な
stat呼び出しの数に影響される ripgrepは、システムコールを最小限に抑えることを目標にした再帰ディレクトリイテレータを使用する.gitignoreの処理にはコストがある- 各ディレクトリで ignore ファイルを探す必要がある
- ignore パターンをコンパイルする必要がある
- すべての候補パスにパターンを適用する必要がある
- Linuxカーネルリポジトリには 4,640 個のディレクトリと 178 個の
.gitignoreファイルがあった ripgrepは.gitignoreの意味をより完全にサポートしようとしており、最後に定義されたマッチングパターンを優先するucgは.gitignoreの代わりにホワイトリストベースの glob 規則を使うため高速なことがあるが、未知の拡張子のファイルを取りこぼす可能性がある
正規表現エンジンの違い
- 正規表現エンジンは大きく2種類に分かれる
- バックトラッキングベース: 機能は豊富だが、一部の入力では指数時間で遅くなることがある
- 有限オートマトンベース: 機能は制限されることがあるが、検索テキスト長に対して線形時間を保証する
- ツールごとのエンジンは次の通りである
- GNU grep、
git grep: 独自の有限オートマトンベースのエンジン ripgrep: Rust regex ライブラリ、有限オートマトンベースag、ucg: PCRE ベースのバックトラッキングpt、sift: Go regex ライブラリ、有限オートマトンベース
- GNU grep、
agとucgは PCRE の利用により、最悪時のバックトラッキング動作にさらされる可能性がある- 例のパターン
(a*)* cは PCRE ベースのツールで問題を引き起こし得るが、他のベンチマーク対象ツールは問題なく処理する
リテラル最適化と SIMD
- 単純な文字列検索では、正規表現エンジンより リテラル検索の最適化 のほうが重要になることがある
- Boyer-Moore は古典的な部分文字列検索アルゴリズムであり、候補位置をすばやく見つけるために
memchrのようなルーチンを活用できる memchr実装は SIMD 命令で一度に 16 バイトを検査することが多く、数 GB/s のスループットを出せる- Rust regex ライブラリは、パターンから prefix・suffix のリテラルを積極的に抽出する
foo|bar(a|b)c[ab]foo[yz](foo)?bar(foo)*bar(foo){3,6}
- 正規表現全体が単一リテラルまたはリテラル alternation に分解できるなら、中核の正規表現エンジンをまったく使わないこともある
ripgrepは行単位で結果を出力する特性を活かして、inner literal も抽出する- 例:
\w+foo\d+ではfooを先に見つけ、候補行だけを正規表現で検証する
- 例:
- 複数リテラル検索では、GNU grep は Commentz-Walter 類似アルゴリズムを使い、Rust regex は Aho-Corasick または Teddy SIMD アルゴリズムを使う
- Teddy は Intel Hyperscan 由来の SIMD ベース多重パターン検索アルゴリズムで、
ripgrepが GNU grep を上回る中核最適化の1つである
検索方式: 行単位検索を避ける
- 素朴な実装ではファイルを1行ずつ読み、各行にパターンを適用するが、ほとんどの検索ではマッチはまれなため非効率である
- 検索ツールは通常、大きなバイトバッファをまとめて検索する
- ファイルをメモリマップする
- ファイル全体をメモリに読み込む
- 固定サイズの中間バッファで段階的に検索する
ripgrep、GNU grep、git grepは段階的検索をサポートし、ファイルとストリームの両方に適用できる- 段階的検索は実装が難しい
- 行番号の計算
- バッファが行の途中で終わる場合の処理
- 長い行の処理
- invert match の処理
- マッチ周辺のコンテキスト出力処理
ripgrepは実装の複雑さを受け入れて段階的検索を採用しており、ベンチマークでは多数の小さなファイル検索でメモリマップより高速な結果を示している
出力と並列性
- 並列検索では、各スレッドがそのまま出力すると、異なるファイルの結果が混ざる可能性がある
- すべての並列コード検索ツールは、検索結果をメモリ上の中間バッファに書き込み、出力段階だけを直列化する
- この方式により、検索スレッドは実際の検索を並列に実行できる
- 欠点は、すべての行がマッチする2GBファイルのような場合、メモリ使用量が大きくなりうる点である
ripgrepは、stdinまたは単一ファイルの検索では、中間バッファなしでstdoutに直接書き込む
ベンチマーク方法論
- ベンチマークは、エンドユーザーの課題を基準に次のように分けられている
- 大規模コードリポジトリの検索
- 単一の大きなファイルの検索
- 検索パターンは、単純なリテラル、alternation、軽い正規表現に偏っている
- ツールごとにデフォルト動作が異なるため、公平な比較のために行番号、Unicode、
.gitignore、ホワイトリストなどの条件を揃えるようにしている - ベンチマーク対象のバージョンは次のとおり
ripgrepv0.1.2- GNU grep v2.25
git grepv2.7.4agcommitcda635, PCRE 8.38ucgcommit487bfb, PCRE 10.21 JITptcommit509368siftcommit2d175c
ackは当時、他のツールより大幅に遅かったため除外された- ベンチマークランナーは、Python 3.5以上を必要とする
benchsuiteで、ripgrepリポジトリに含まれている - 各コマンドは測定前に3回のウォームアップを実行し、OSのページキャッシュにコーパスが載るようにした
- 各コマンドは10回測定し、平均と標準偏差を記録した
- 実行環境は Amazon EC2
c3.2xlarge、Ubuntu 16.04、Xeon E5-2680 2.8GHz、メモリ16GB、80GB SSDである - 設定ログ、要約結果、raw CSVも公開されている
Linuxカーネルコード検索結果
- コード検索ベンチマークは、ビルド済みLinuxカーネルリポジトリ commit
d0acc7で実行された - ビルド済みカーネルリポジトリを使った理由は、ビルド成果物がリポジトリに残ることで、検索結果の関連性や性能に影響を与えうるためである
linux_literal_defaultでの単純リテラルPM_RESUME検索は、各ツールのデフォルト動作の違いを示しているrgは.gitignoreを尊重し、隠しファイル・バイナリファイルをスキップするagとptも似ているが、行数を数えるucgは.gitignoreを読まず、ホワイトリストベースで検索するsiftはデフォルトではほぼすべてを検索するgit grepは、git indexから検索対象ファイル集合を取得できる利点がある
.gitignoreを尊重することは、結果の関連性を高める一方で、性能面ではコストになることがあるlinux_literalでは、rg (whitelist)はucgとほぼ同等の性能を示し、rg (ignore)はgit grepと近い水準だったrg (ignore) (mmap)とag (ignore) (mmap)は、メモリマップの使用により遅くなり、同条件ではrg (ignore)の方がはるかに速かった- ローカルマシンでもメモリマップ版はより遅かったが、EC2ほど差は大きくなかった
Unicodeと大文字小文字検索
linux_literal_caseiでは、ptは-iをGo regexpの(?i)として処理したため大幅に遅くなったsiftは、パターンと検索ブロックを小文字に変換する方式を使ったため、遅くなり方は比較的小さかったが、この最適化はASCIIの大文字小文字しか扱えず、Unicodeの大文字小文字処理としては不正確であるripgrepは、大文字小文字を無視する検索を可能なリテラルの組み合わせに変換し、Teddyで候補位置を高速に見つけるlinux_unicode_wordの\wAh検索は、Unicode対応の\wがµAhのような結果を拾えるかを確認するものだ- Unicodeの切り替えが可能だったのは
rgとgit grepだけで、ag、pt、sift、ucgはASCII専用の\wを使っていた git grepはUnicode対応を有効にすると大きな性能コストが発生したが、ripgrepでは性能低下はほとんどなかったripgrepは、UTF-8デコードを有限状態機械に組み込み、別個のデコード段階なしにUTF-8バイト列へ直接マッチさせる
正規表現の複雑さによる違い
[A-Z]+_RESUMEのようにリテラルsuffixを持つ正規表現では、rgとucgは_RESUMEを使って候補を高速に見つけるERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVTのようなリテラルalternationでは、ripgrepはTeddyを使い、中心となる正規表現エンジンをまったく使わないことさえある- 大文字小文字を無視するalternationでも、
ripgrepは大文字小文字の組み合わせprefixを作ってTeddyで候補を見つけ、候補だけを完全な正規表現で検証する \p{Greek}検索では、Rust regexとGo regexだけがそのUnicodeプロパティに対応しており、rgはptやsiftよりはるかに高速だった\p{Greek}の大文字小文字無視検索では、siftはマッチを報告できず、ptはUnicodeの大文字小文字処理を正しく行えなかった\w{5}\s+...のようにリテラルを含まないパターンでは、regexエンジンの性能が直接表れるrgはUnicode対応時でも高速な方だったgit grepはUnicode対応時に大きなコストを負った- Unicode DFAはASCII DFAよりはるかに大きなNFA状態集合を扱い、例としてASCIIでは約250個、Unicodeでは約77,000個のNFA状態になる
単一の大きなファイルの検索
- 単一ファイルのベンチマークには OpenSubtitles2016 のサンプルが使われた
- 英語サンプルは約1GB
- ロシア語サンプルは約1.6GB
- この領域では、正規表現エンジンの性能とリテラル最適化がより重要になる
subtitles_literalでは、Sherlock HolmesとШерлок Холмсの検索はいずれもrgが最速だったripgrepは、リテラルについて出現頻度の低いバイトを選び、memchrで使おうとする- 標準的な Boyer-Moore 実装は通常、候補検索に最後のバイトを使う
rgは、よりまれなバイトを選ぶことで、SIMD最適化ループでより長くスキップしようとする
- ロシア語パターンはUTF-8では多くの文字が
\xD0または\xD1で始まるため、先頭バイト検索が非効率になる可能性がある rgは、事前計算された256バイト頻度表を使い、\xD0や\xD1よりも出現頻度の低いバイトを優先する- 単一の大きなファイルでは、メモリマップを一度作ればよいため、
rgのメモリマップ検索はrg (no mmap)より約25%速かった
単一ファイルでのUnicodeとalternation
subtitles_literal_caseiでは、rgはUnicodeの大文字小文字無視検索を正しく処理しながら高速だった- GNU grepはUnicodeの大文字小文字無視検索で大きなコストを負った
- ロシア語の大文字小文字無視検索では、
grep (ASCII)は-iを事実上無視しているように見え、agは0件のマッチを報告した subtitles_alternateでは、複数の人物名を含むalternation検索で、rgが英語・ロシア語の両方で最速だった- 英語のalternationでは、
rgはGNU grepより約1桁速かった subtitles_alternate_caseiでは、rgは前よりかなり遅くなったが、英語ではなお他のツールを上回った- この場合は、Teddyが処理するにはリテラル候補が多すぎるため、
rgはTeddyの代わりにAho-Corasickへ切り替える ripgrepは、transition tableベースの「advanced」Aho-Corasickを使い、入力バイトごとに1回の遷移を実行する
inner literal とリテラルのないパターン
\w+\s+Holmes\s+\w+のようなパターンは prefix・suffix リテラル最適化を避けるように構成されているが、内部リテラルHolmesを活用できるripgrepと GNU grep は inner literal 最適化を行うripgrepは Rust regex のregex-syntaxを活用し、パターン AST からリテラルを抽出する- ロシア語版
\w+\s+Холмс\s+\w+では、Unicode を正しくサポートするツールだけが意味のある結果を出せた - リテラルがまったくない長い
\w{5}\s+...パターンでは、rgは英語で最速クラスであり、GNU grep の Unicode 対応版は英語で 90 秒以上、ロシア語で 4 分以上かかったため除外された ripgrepは UTF-8 デコードを DFA に組み込む方式で、Unicode サポートを維持しつつ性能を確保している
追加ベンチマーク
everythingは Linux リポジトリで.*によってすべての行をマッチさせる非現実的なテストrgは 22,065,361 行を 1.081 秒で報告したagとptはすべての行を報告せず、マッチ数の制限があるように見える
nothingは.*に invert match を適用し、どの行も報告しないテストrgは 0.302 秒、git grepは 0.905 秒を記録したptとucgは invert search をサポートしていない
contextは英語字幕コーパスでSherlock Holmesの前後 2 行の文脈を出力するrgは 0.612 秒、siftは 0.717 秒でほぼ同等だったucgはこの機能をサポートしていない
hugeは 9.3GB の英語字幕全体でSherlock Holmesを検索するrgは 1.786 秒、GNU grep は 5.119 秒、siftは 3.047 秒を記録したucgは行数カウント条件で 1,543 行しか報告せず誤った結果を出しており、2GB 超のファイル検索で問題が発生したと疑われる
結論
ripgrepは Linux カーネルリポジトリの検索で、すべてのベンチマークに常に勝ったわけではないが、性能と正確性の両面で他のツールが明確に優位だとは言いにくかったgit grepは一部の単純なケースで数ミリ秒先行することがあったが、パターンが複雑になったり Unicode が必要になったりすると、ripgrepが大きく上回る場合があったripgrepのコード検索性能には、次の要素が寄与しているstat呼び出しの最小化を目標にした高速なディレクトリ走査RegexSetを用いた.gitignoreglob マッチング- Chase-Lev work stealing queue による作業分配
- 多数の小さなファイルの検索でメモリマップを使わないという選択
- 高速な正規表現エンジン
- 単一ファイル検索では、
ripgrepはすべての主要ベンチマークで最速か、大差をつけて先行した - 単一ファイル性能には、疎バイトベースの
memchr、Teddy SIMD、Aho-Corasick、UTF-8 デコード内蔵 DFA が影響している - Unicode 機能を必要とするベンチマークでは、
rg、GNU grep、git grepだけが意味のあるサポートを示し、GNU grep とgit grepは概して大きな性能コストを伴った - メモリマップは Linux x86_64 基準で、多数の小さなファイルの並列検索では不利であり、単一の大きなファイルの検索では有利で、VM 環境では追加のペナルティが発生する可能性があった
1件のコメント
Hacker News の意見
確かに速く、fzf との組み合わせをいつも勧めたくなる
まず
ripgrepで探し、その結果のファイル+テキストに対してファジー検索を重ね、batで文脈を表示する PowerShell 関数として使っている複数のリポジトリが混在するプロジェクトで、「どこかにあるのは分かっているが、正確な場所や名前が分からない」ときに非常に素早く絞り込める
この方法は https://github.com/junegunn/fzf/blob/master/ADVANCED.md に載っているもので、全部を使わないとしても、アイデアを得るために目を通す価値がある
fzfと統合することを勧めるテキストファイルだけでなく、PDF や zip などさまざまなファイル形式までファジー検索できる
詳細は https://github.com/phiresky/ripgrep-all/wiki/fzf-Integration にある
rgの結果をfzfで選び、選択したファイルと行番号をパースして$EDITOR +"${linenumber}" "$file"で開く方式だ電動グラインダーではなく手でコーヒー豆を挽いているようなものだ
fzfを使うと、Git に追加するファイルを大量に選びつつ、一部はスキップできるgitconfigの[alias]にfza = "!git ls-files -m -o --exclude-standard | fzf -m --print0 | xargs -0 git add"を入れると、git fzaで変更済みまたは未追加のファイル一覧が表示され、スペースで項目をトグルしながら次へ移動できるこのエイリアスと fzf+fd が、ワークフローの一部をかなり速くしてくれる
macOS で zsh 設定に入れるものをまとめたガイドもある: https://gist.github.com/aclarknexient/0ffcb98aa262c585c49d4b...
ripgrepをほぼ同じように使っている数百のリポジトリがあるコードベースで、ファイルやプロジェクトを絞り込む出発点として使い、その後さらに掘り下げる
Emacs で
ripgrepを project.el と dumb-jump パッケージで使っている最も人気のある方法ではないかもしれないが、全体としての体験はかなり満足している
package-installでdumb-jumpをインストールし、(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)だけ設定すればよいPython プロジェクトで
M-.またはC-u M-.で識別子の定義を探すと、dumb-jumpが現在のプロジェクトとファイル形式に合わせてrgコマンドを実行し、結果を Xref バッファに表示するagもサポートしており、agやrgがなければgrepに戻るが、ホームディレクトリ全体を探すときは予想どおり遅くなることがあるripgrepはかなり簡単に使える外部パッケージが必ず必要というわけではなく、大きなディレクトリで遅い
grepの代わりに使うには(setq xref-search-program 'ripgrep)を設定すればよいすると
C-x p g foo RETのようなプロジェクト検索が、現在のプロジェクトでrg -i --null -nH --no-heading --no-messages -g '!*/' -e fooの形で実行される結果は Xref バッファに出るので、
n、p、RET、C-oなどのキーで次/前のマッチへの移動、ソースへのジャンプ、分割ウィンドウ表示がしやすいripgrepの作者として見ると、その正規表現は実際に実行してはいないが、--pcre2 フラグは外してよさそうだ2つ目と3つ目の
\bアサーションも外してよさそうで、1つ目は必要かもしれないripgrepを使い、evil-collectionのバインディングもあるので快適に使える: https://github.com/Wilfred/deadgrepそういうときは、以前なら
rgrepを使っていた場面だ興味深いのは、VS Code の検索も今では Node.js ラッパーを通じて
ripgrepで動作していることだhttps://www.npmjs.com/package/@vscode/ripgrep
ripgrepは入れられない環境なら、これは非常に良いVS のインストールパス内で
rgバイナリを見つけられる。少なくとも私の Windows の職場環境では可能だったripgrepを2年ほど使ってきて、今ではなくてはならないツールになったgrepから乗り換えた主な理由は使いやすさだったデフォルトで
.gitignoreのルールを尊重し、隠しファイル/ディレクトリやバイナリファイルを飛ばしてくれるため、rg search_term directoryは対応するgrepコマンドよりずっと良く、速度向上はおまけだマッチが長すぎてターミナルがめちゃくちゃになるときは、
-M 1000のように -M オプションをよく使う-Mは本当に素晴らしい見たくない minified ファイルの結果を無視するときに特に便利で、
-g *.csのように -g オプションで特定の拡張子のファイルだけを検索するのも良い単独で実行できるポータブルなバイナリである点も有用で、新しいマシンで作業するときに実行ファイルを置き、
grepのエイリアスをrgにしておけば、慣れたようにgrepと打ってもrgが実行される2023年でもなお当てはまる話かもしれないが、問題は並列化された
grep代替ツール、たとえばripgrepやagが従来のgrepより速すぎて、相互のわずかな速度差が判断基準になりにくいということ90万行のコードベースで Emacs 内から
agを使っているが、16コアの Ryzen Threadripper 2950X では実質的に即座に終わる1秒未満を「もう少し短い1秒未満」に縮める必要は感じない
新しい
grep系ツールの重要な特性は速度ではなく、別の方法で評価・比較すべきagにはかなり大きな性能の崖があり、ブログ記事でも確認できるただしワークロードは人それぞれなので、場合によっては性能差が重要でないこともある
90万行はそれほど大きい部類ではなく、単純なクエリなら、素朴すぎない
grep系ツールのほとんどは非常に速く処理する別の比較基準で見ると、
agはほぼ延命状態で、Debian から削除されかけたところを誰かが救ったように見える: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=999962ブログ記事ではUnicode対応も比較しているが、
agには実質的に Unicode 対応がない。全員に重要とは限らないが、非性能面の比較基準としては十分検索時間はファイルがディスクから読み込まれる時間だけかかり、その後の差は意味を持ちにくい
ファイルがキャッシュにある場合は、検索時間よりファイルシステムを移動してコマンドを入力する時間のほうが支配的なので、やはり性能差は意味を持ちにくい
タイトルには (2016) が必要
これは元の発表記事であって、新情報ではない
“Ripgrep – A new command line search tool” https://news.ycombinator.com/item?id=12564442 (740 points | Sept 23, 2016 | 209 comments) — 速度に関する議論もある
“Ripgrep is faster (2016)” https://news.ycombinator.com/item?id=17941319 (98 points | Sept 8, 2018 | 40 comments)
qgrepよりは速くない両者の動作方式は大きく異なり、
qgrepはre2ベースだが、速度が出るのはインデックスがあるため大きなファイルリポジトリでは、毎回すべてのファイルを走査するより
qgrepとインデックスを使うほうが理にかなっているのに、なぜ人々がqgrepという選択肢を忘れるのか不思議ただし UTF-8 で複数行マッチングが必要なら、
ripgrepは別の PCRE2 ライブラリにフォールバックする必要があるので、それほど速くないと思うripgrepの作者として言うと、qgrepがインデックスを使うため、インデックスを使わないツールより有利なのは確かその代わりインデックスを設定して維持する必要があるため、UX は「ただ検索を実行する」ほど単純ではない
人々が
qgrepを使わない理由は、「自分には grep でも十分速い」という理由でripgrepを使わないのと似ている小さな検索対象では、
ripgrepとgrep、あるいはqgrepとripgrepの速度差を体感できないことが多いLinux カーネルの検索を
ripgrepが 100ms 未満で終えるなら、標準的な対話的利用でインデックス付きツールに乗り換えるほど不便かどうかは状況次第だが、たいていはそうではないはずripgrepにインデックス機能を追加するアイデアを考えたことはある: https://github.com/BurntSushi/ripgrep/issues/1497そして複数行検索はPCRE2を必要としない。標準の正規表現エンジンにも Unicode 対応があり、PCRE2 なしでビルドしても複数行検索のサポートは維持される
ripgrepから ugrep に乗り換えてから、振り返らなくなった速度も同程度だが、ファジーマッチングがあり、コードレビューに使える TUI もあり、PDF や圧縮ファイルの中も検索できる
オプションで Google 検索構文を使えるのも便利
https://ugrep.com
ripgrepの熱烈なファンだが、最近ripgrepにはない機能であるzip 圧縮内部の検索が必要になり、ugrepを見つけたディスクに展開せずに検索できる
数百万個の小さなテキストファイルからなる圧縮コーパスを扱っているが、全体をファイルシステムに展開する必要がなくなって助かっている。ファイルシステムによってはこの規模が厳しい
どちらのツールにも感謝しているし、それぞれの作者にも感謝している
grepで Google 検索構文を使い始めたら、結果の大半が何かを売ろうとしてきそうで怖いugrepとripgrepの作者たちが Reddit で何年も言い争っていたらしい投稿を見たたとえば https://www.reddit.com/r/programming/comments/120wqvr/ripgre...
ただのオープンソースツールの話なのに、少し奇妙に感じる
fzfに渡すより良いのか気になる私には
fzfの設定可能性と柔軟性に勝つのは難しそうに見えるキラー機能は既存の grep コマンドラインオプション互換性のように思える
まったく新しいオプション群を覚える必要がないのはかなり良い
なぜ
grepは置き換えられたり改善されたりしないのか気になるこの話題も、もう少し古くなってきた気がする
慣性、互換性、変化への抵抗、イノベーターのジレンマのようなもの。否定的に言っているわけではなく、自分にもすべて当てはまる
互換性については FAQ を見ればよい: https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#pos...
快適で、周囲の作業環境によく合っていて、わざわざ替えて全部合わせ直す理由がない
Razer のような椅子が近くにすでにあって、服を預けているという点までなら、この比喩は成り立つ
xyzというプログラムが必ず存在し、この引数を受け取り、正確にこのように動作しなければならない」といった奇妙な結果が生まれたripgrepのような複数の代替ツールを使えるgrepコマンド自体を別のユーティリティに置き換えようという話なら、得られる価値に比べて壊れるものが多すぎるように見えるより速い
grepが欲しい人は別のツールを使い、従来のgrepを使う人は使い続ければよいので、すでに理想的な状態に近いgrepはあらゆる種類のファイルからテキストを探す汎用ツールであり、UNIX 標準に組み込まれている一部のプログラマーはソースコード検索に使うが、他の人はソースコードとは無関係なテキスト検索やスクリプトで使っており、絶対にクラッシュしないことを期待している
一方
ripgrepは主にソースコードリポジトリ検索のために設計された、専門的で主張の強いツールである汎用テキスト検索をさらに速くする余地はあまりない。
mmap()を使えば切り詰められたファイルでクラッシュするリスクがあり、正規表現の表現力を落とせば速くできるかもしれず、すべての locale と文字セット対応を捨てて UTF-8/UTF-16 だけをハードコードすることもできるが、そうすべきではないPortage で探してみると、PDF や doc など他の文書まで扱うバージョンもあるようだ
https://github.com/phiresky/ripgrep-all