Grepを待つのはもうやめよう:fzfとripgrepによる実践的なプロダクション環境ガイド

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

問題点:標準ツールが限界に達するとき

以前の私は、巨大なログファイルをgrepがクロールするのを待つために、毎日何分もの時間を無駄にしていました。長年、私のワークフローはfindgrepの定番コンビに頼っていました。これらは信頼性が高く、どこにでもプリインストールされていますが、プロジェクトの規模が大きくなると力不足を感じるようになります。10台以上のVPSインスタンスを管理し、数ギガバイトのログを扱うようになると、これらのレガシーなツールがボトルネックになり始めました。

6ヶ月前、私は検索スタックをfzf(コマンドラインのファジーファインダー)とripgrep(高性能検索ツール)に置き換えました。Rustで書かれたripgrep(rg)は、並列処理を活用することで、一貫してGNU grepを凌駕するパフォーマンスを発揮します。一方、fzfは対話的なレイヤーを追加し、入力しながら結果を絞り込むことができます。この組み合わせは、検索時間を数秒短縮するだけでなく、ファイルシステムのナビゲーション方法を根本から変えてしまいます。

本当の利点は、fzfの「ファジー(曖昧)」ロジックにあります。正確なファイルパスを覚える必要はもうありません。バラバラな数文字を入力するだけで、fzfが瞬時に数千のファイルから候補を絞り込みます。ripgrepの出力をfzfにパイプすることで、ターミナルに最適化された独自の検索エンジンを構築できるのです。

インストール:環境を整える

ほとんどのモダンなLinuxディストリビューションでは、これらのツールが公式リポジトリに含まれています。ただし、最新の機能を利用できるよう、バージョンを確認することをお勧めします。

1. Ripgrep (rg) のインストール

UbuntuやDebian (20.04以降) では、aptを使用します:

sudo apt update
sudo apt install ripgrep

FedoraやRHELシステムの場合:

sudo dnf install ripgrep

古いディストリビューションを使用している場合は、GitHubからバイナリを直接取得するか、Cargoを使用できます:

cargo install ripgrep

2. Fzf のインストール

aptでも動作しますが、私はgitによるインストール方法を好みます。最新バージョンを入手でき、オートコンプリートなどのシェル拡張機能の設定も簡単になるからです。

git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install

インストール中のプロンプトにはすべて「Yes」と答えてください。これにより、.bashrcまたは.zshrcが自動的に更新され、CTRL-T(ファイル検索)やCTRL-R(コマンド履歴検索)などの不可欠なショートカットが有効になります。

設定:各ツールを連携させる

インストールしただけでは始まりに過ぎません。デフォルトでは、fzfは標準のfindコマンドを使用してファイルをリストアップします。これを改善しましょう。ripgrepの方が高速で、.gitignoreのルールも自動的に考慮してくれるため、fzfでripgrepを使用するように設定します。

Ripgrepを使用するようにfzfを設定する

~/.bashrcまたは~/.zshrcファイルに以下の行を追加します:

# ジャンクファイルや隠されたgitデータを無視してファイルを検索するためにripgrepを使用する
export FZF_DEFAULT_COMMAND='rg --files --hidden --glob "!.git/*"'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"

この設定により、CTRL-Tを押したときに、数千もの.git内部ファイルが表示されることがなくなります。一方で、.env.htaccessのような重要な隠しファイルは引き続き表示されます。

強力な「検索して開く」関数

私が最もよく使うワークフローの一つは、特定の文字列を検索し、そのファイルの正確な行番号で開くことです。これを自動化するために、シェルの設定に以下の関数を追加してください:

# Find in File (fif): テキストを検索し、Vimで該当する行を開く
fif() {
  if [ ! "$#" -gt 0 ]; then return; fi
  rg --column --line-number --no-heading --color=always --smart-case -- "$1" | \
    fzf --ansi \
        --delimiter : \
        --preview 'bat --style=numbers --color=always --highlight-line {2} {1} 2>/dev/null || cat {1}' \
        --preview-window 'up,60%,border-bottom,+{2}+7/2' \
        --bind "enter:become(vim {1} +{2})"
}

注:これは構文ハイライト付きのプレビューを表示するためにbatを使用しています。インストールされていない場合、この関数はcatにフォールバックします。

UIの改善

デフォルトのfzfインターフェースは少し地味です。ボーダーを追加し、レイアウトを反転させることで、より読みやすくできます:

export FZF_DEFAULT_OPTS='--height 45% --layout=reverse --border --color="border:#777777"'

検証:効果を測定する

シェルをリロード(source ~/.bashrc)した後、速度をテストしてみてください。モノレポやLinuxカーネルのソースコードのような大規模なプロジェクトディレクトリに移動し、CTRL-Tを実行します。一瞬で表示されるはずです。

違いをベンチマークする

百聞は一見に如かずです。50,000以上のファイルがあるディレクトリで、これら2つのコマンドを実行してみてください:

# 標準のfind
time find . -name "*.c" | wc -l

# Ripgrep
time rg --files -g "*.c" | wc -l

NVMeベースのVPSでのテストでは、findは約1.2秒かかりましたが、rgはわずか0.08秒で終了しました。これは15倍のパフォーマンス向上です。

実践的なヒントと落とし穴

fzfは強力ですが、数百万行をパイプで流し込むと、インターフェースが重くなることがあります。ターミナルがフリーズした場合は、htopを確認してください。通常、ボトルネックはfzf自体ではなく、最適化されていないソースコマンドにあります。

バイナリファイルにも注意してください。ripgrepはデフォルトでそれらを無視しますが、すべてを強制的に検索するようにすると、プレビューウィンドウに読み取れないゴミが表示される可能性があります。エイリアスには常に--smart-caseを有効にしておきましょう。これにより、大文字を入力しない限り、大文字小文字を区別せずに検索されます。

これらのツールを採用することで、複雑なファイルシステムのナビゲーションに伴う摩擦が解消されます。6ヶ月間使用した今、私は標準的なシェル環境に戻ることはほぼ不可能だと感じています。

Share: