Vimのvimgrepとgrepの違い(内部grepと外部grep)
Vimには全文検索コマンドが2種類あります。Vim標準機能の:vimgrep(内部grep)と、OSのgrepコマンドを呼び出す:grep(外部grep)です。名前が似ていて混同しやすいものの、性質はかなり異なります。
| キー | これだけ覚える |
|---|---|
:vim {パターン} {対象} | 内部grep。環境非依存だが低速 |
:grep {パターン} {対象} | 外部grep。高速だが環境依存 |
set grepprg=internal | 外部grepを内部grepの動作に切り替え |
内部grep(vimgrep)
:vimgrep {検索パターン} {検索対象}
:vim {検索パターン} {検索対象}
Vim標準のExコマンドとして実装されています。Vimさえ動けばOSを問わず同じように使えますが、対象ファイルをすべてメモリに読み込みながら検索するため、動作速度は控えめです。
外部grep(grep)
:grep {検索パターン} {検索対象}
:gr {検索パターン} {検索対象}
OS側のgrepコマンド(Windowsならfindstr)をそのまま呼び出すExコマンドです。実行しているのは基本的に次のようなコマンドで、OSコマンドとしてのgrepの引数がそのまま使えます。
:!grep -n $* /dev/null {検索パターン} {検索対象}
内部grepより高速に動作するのが利点ですが、実行可否や挙動が環境(OSやシェル)に依存します。
比較まとめ
| 比較軸 | 内部grep(vimgrep) | 外部grep(grep) |
|---|---|---|
| 実行速度 | 普通 | 高速 |
| 検索対象 | ファイル(複数行パターン可) | ファイル(コマンド依存) |
| エンコーディング認識 | 自動 | 環境依存 |
| 結果の表示先 | Quickfix/locationウインドウ | Quickfix/locationウインドウ |
| ヒット件数の表示 | あり | あり |
使うコマンドを変更する
外部grepで実際に呼び出すコマンドはgrepprgオプションで指定されています。
set grepprg=grep\ -n\ $*\ /dev/null " Linux/Mac
set grepprg=findstr\ /n " Windows
逆に、外部grepの呼び出しそのものを内部grepの動作に切り替えることもできます。
set grepprg=internal
近年はripgrepのような高速な外部検索ツールをgrepprgに設定して使うケースが増えています。
set grepprg=rg\ --vimgrep\ --smart-case
set grepformat=%f:%l:%c:%m
ripgrepは.gitignoreを自動的に尊重して不要なファイルを除外してくれるため、大規模なリポジトリではvimgrep・標準grepよりも快適に使えることが多くなります。
具体的な検索コマンド例
複数ファイルを対象にした具体的な使い方はvimgrepで複数ファイルを検索する記事、開いているバッファだけを対象にしたい場合はbufdo + vimgrepの記事を参照してください。
数百ファイル規模のプロジェクトではvimgrepの速度に不満を感じることがあり、grepprgをripgrepに切り替えてから体感速度が大きく改善しました。設定ファイルのようなごく少数のファイルを検索する分にはvimgrepのままでも問題は感じていません。
まとめ
普段使いなら環境非依存で扱いやすいvimgrep、大規模な検索が必要ならgrepprgを高速な外部ツールに切り替えるのがおすすめです。プロジェクトの規模に応じて使い分けると便利です。