vimのgrepの設定と使い方

vimやgvimでgrepを使用する方法は内部grep(vimgrep)と外部grepの2種類あります。

内部grep(vimgrep)は vimに普通のファイルとしてバッファに読み込んでから grep同等の処理を行っているため、速度の問題は対処しようがありません。

grepの結果ヒットしたファイルが2000ファイルあれば2000ファイルを読み込んだのと同じ処理が行われますので、それだけのバッファを確保します。

大抵は問題有りませんが、大量のファイルを vimgrepしてヒットすると一部の動作やバッファ管理系などのプラグインが重くなる事もあります。

外部grep(GNU grep、cygwin grep等)は、速度は圧倒的に速いのですが、日本語(全角文字)の扱いに若干問題が出てくる事があります。

たとえばcp932のファイルの「だめ文字」や、vimの内部エンコーディングと異なる文字エンコーディングの日本語ファイルを扱いたい場合などは、「QFixGrep」やnkfなどの日本語grepヘルパーが必要になります。

英数字しか使用しないなら全く問題はありません。

またBOM付きutf-8ファイルでは最初の一文字が外部grepで検索できないことがあります。

これはBOMが文字ではないバイト列としてファイルの先頭に埋め込まれているためで、正規表現で行頭を検索する場合などに問題となります。

特にWindowsの場合はメモ帳でutf-8のファイルを開いて保存すると強制的にBOM付きへ変換されてしまうので気をつける必要があります。

単純に英数字の場合は外部grep(:grep)を使用して、日本語の場合は内部grep(:vimgrep)を使用すると問題が起きにくいでしょう。

他のエディタでは異なる文字コードのファイルが混在していると grepできなかったりする事も多いのでvimgrepはアドバンテージになるかもしれません。

以下には、双方の設定と簡単な使い方、外部grepでの日本語の文字化け、Windowsの vim/gvimをUTF-8化した時などの外部grepの問題と対処法について書かれています。

内部grep(vimgrep)の使い方

vim 7.0以降ならコマンドモードから vimgrep が使えます。

以下のように実行すると、"検索文字"をカレントディレクトリのtxtファイルから検索して、最初にマッチした行に移動します。

:vimgrep 検索文字 *.txt

最初にマッチした場所へ移動したくない場合は / で検索ワードを囲んで j オプションを指定します。

:vimgrep /検索文字/j *.txt

いずれにしても / 自身を検索したい場合は、/ をエスケープしてやる必要があります。

再帰検索を行いたい場合は、ファイル名を **/*.txt のように **/ 付で指定します。

:vimgrep 検索文字 **/*.txt

検索した後は :copen でQuickfixウィンドウを開いて、検索結果を一覧表示、選択が可能です。

Quickfixウィンドウを開かなくても :cp(cprev)、:cn(cnext) で前後の結果へジャンプできます。

検索後に自動でQuickfixウィンドウを開くには次のように実行します。

cw は cwinの略表記です。

:vimgrep 検索文字 *.txt |cw

また、次のように設定すれば、コマンドから grep と打ってもvimgrepが使用されます。

set grepprg=internal

外部grepの設定

unix系の場合は設定は不要ですので「外部grepの使い方」へ進んでください。

Windows2000/Xp/Vistaの場合デフォルトでは findstrが設定されますが、findstrはcp932専用で正規表現も貧弱ですので出来れば外部grepを使用する事をおすすめします。

英数字のみの検索かcp932のファイルしか扱わないなら findstrでも問題はありません。

Windowsの外部grepにはGNU grep互換であれば使用可能です。

Git for Windows, MSYS2, cygwinを利用している場合は、各パッケージに含まれるgrepを使用するように設定可能です。

findstr

Windows(2000以降)のデフォルトとして以下のように設定されます。

set grepprg=findstr\ /n

findstrのオプションや正規表現についてはWindowsのヘルプでfindstrを検索して下さい。

findstrはcp932専用ですので、英数字以外はUTF-8などで検索できない事が多々あります。

抽出済みgrep(MSYS2)

以下にMSYS2から抽出したgrepバイナリがあります。

grep-msys2.zip

zipを解凍してパスを通すか$VIMへコピーして、grepprgを設定します。

set grepprg=grep\ -n

Vimの:!grepでエラーが出る場合はフルパスで指定するか、Vim上でPATHを通します。。

" フルパス指定

set grepprg=C:/path/to/bin/grep\ -n

" Vim上でパスを通す

let $PATH .= ';C:\path\to\bin'

PATHは使用環境に合わせて修正してください

Git for Windows

Windowsでgit(Git for Windows)を使用しているならgitのgrep.exeが使用可能です。

https://git-for-windows.github.io/

パスが通っている場合はgrepprgを設定するだけで動作します。

set grepprg=grep\ -n

Vimの:!grepでエラーが出る場合はVim上でPATHを通します。

" Git for Windows

let $PATH .= ';C:\Program Files\Git\usr\bin'

PATHは使用環境に合わせて修正してください

MSYS2

Windows用Gnuツールが以下で配布されています。

https://msys2.github.io/

パスが通っている場合はgrepprgを設定するだけで動作します。

set grepprg=grep\ -n

Vimの:!grepでエラーが出る場合はVim上でPATHを通します。

" MSYS2 64bit

let $PATH .= ';C:\msys64\usr\bin'

" MSYS2 32bit

let $PATH .= ';C:\msys32\usr\bin'

PATHは使用環境に合わせて修正してください

cygwin

cygwinをインストールしていてコマンドプロンプトから grepが使える場合は、次のように指定します。

set grepprg=grep\ -n

Vimの:!grepでエラーが出る場合はVim上でPATHを通します。

let $PATH .= ';C:\cygwin\bin'

pathは環境に合わせて指定して下さい。

GnuWin32

Windows用32bitのGnuツールが以下で配布されています。

http://gnuwin32.sourceforge.net/

インストールしたら、実行ファイルへパスを通してmygrepprgを設定します。

set grepprg=grep\ -n

Vimの:!grepでエラーが出る場合はVim上でPATHを通します。

" 64bit環境

let $PATH .= ';C:\Program Files (x86)\GnuWin32\bin'

" 32bit環境

let $PATH .= ';C:\Program Files\GnuWin32\bin'

PATHは使用環境に合わせて修正してください

外部grepの使い方

設定が済んだら、以下のように実行すると、"検索文字"をカレントディレクトリのtxtファイルから検索します。

:grep 検索文字 *.txt

検索した後は :copen でQuickfixウィンドウを開いて、検索結果を一覧表示、選択が可能です。

Quickfixウィンドウを開かなくても :cp(cprev)、:cn(cnext) で前後の結果へジャンプできます。

オプションについては、使用する各grepのマニュアルを参照して下さい。

再帰検索のオプションは大抵 -r (findstrは/s)です。

:grep -r 検索文字 *.txt

検索後に自動でQuickfixウィンドウを開くには次のように実行します。

cw は cwinの略表記です。

:grep 検索文字 *.txt |cw

ASCII文字(英数字)か内部エンコーディングと同じファイルしか grep しないならほとんど問題はありませんが、そうでないなら 外部grepの問題点 を参照してください。

外部grepの問題点

基本的に内部エンコーディングと同じファイルを扱っている限り、日本語はfgrep(固定文字列検索)で行うようにしていればほとんど問題なく扱えます。

内部エンコーディングと異なるファイルを日本語検索する場合は nkfやVimスクリプト等で検索文字列をエンコーディング変換する必要があります。

またWindows版vim/gvimの内部エンコーディングをutf-8化している場合は日本語ファイル名(path)にも気をつける必要があります。

ダメ文字」については正規表現で検索は出来ませんが fgrep(固定文字列検索) を使用すると検索可能です。

日本語でgrepが必要になるケースは少ないと思うので、日本語の場合は通常fgrepを使用する方が良いかと思います。

Windows / Linux 共通の問題

  • utf-8のBOM付きの場合、最初の一文字が検索できない事がある。
    • BOMは文字ではないバイト列としてファイルの先頭に埋め込まれているため、正規表現で行頭を検索する場合などは検索不可。
  • ucs2-leなどリトルエンディアンのファイルは検索できない。

Windowsの場合

Windowsでvim/gvimの内部エンコーディングを変更して、外部grepを使用した場合の問題点を表にまとめました。

Windowsでのデフォルト内部エンコーディングはcp932(Shift_JIS)です。

  • 「日本語ファイル名」にはpathも含みます。
    • 指定不可はコマンドモードから日本語ファイル名(path)が指定できないだけなので、カレントディレクトリ以下のファイルしか検索しないなら問題はありません。
  • 日本語検索不可の場合、ASCII文字で検索することは可能ですが、日本語部分のgrep表示は文字化けしています。
  • Windowsのメモ帳でutf-8のファイルを保存すると、BOM付きに強制変換するので、最初の一文字が検索出来なくなる事があります。

具体的なダメ文字については「Shift_JIS(cp932)の「ダメ文字」」を参照して下さい。

Linux(Ubuntu)の場合

shellと内部エンコーディングが基本的に一致しているので、問題はutf-8以外のファイルの日本語検索不可だけになります。

結論

速度的に問題ないならvimgrepを使用します。

速度が問題の場合や、検索対象ファイル数が多くて重くなったり、最後の編集位置などを消されたくない場合は外部grepを使用します。

速度的な問題から外部grepを使用する場合で、うまく外部grepで扱えない事があるのは以下のような場合です。

以下のような場合は「QFixGrep」やnkfなど、何らかの日本語grepヘルパーなどが必要になります。

Windows(vimの内部エンコーディング cp932)の場合

  • cp932のファイルで「ダメ文字」を扱いたい場合
  • cp932以外のファイルを外部grepで日本語検索したい場合

Windows(vimの内部エンコーディング utf-8)の場合

  • 日本語を含むファイル名やpathが含まれている場合
  • utf-8以外のファイルを外部grepで日本語検索したい場合

Linux(Ubuntuでvimの内部エンコーディング utf-8)の場合

  • utf-8以外のファイルを外部grepで扱いたい場合
    • nkfを使用して変換する方法もある