EMacs の M-x grep で漢字を使いたい

何を今更なお話ですが、これまで出来なかったんです。プログラミング関係でgrepする時はあまり漢字は探さないので特に必要が無くて、そのうち時間が出来たら調べようと思っているうちに随分時間が経ってしまいました。

うちは小物のツールはCygWinで調達してます。grep.exe もCygWinのものを使ってます。shell環境はemacs(NTemacs)のshell-modeでCygWinのbashを動かしています。

shell-modeで echo $LANG とすると、そっけなく JPN と出ます。*shell*バッファのcoding-systemはutf-8と表示されています。

WideStudio向けのソースはutf-8で書くのですけれども、昔作ったソースを始めVisual C++や組み込みシステム向けのコンパイラを使うプロジェクトのソースはshift-jisです。仕事によってはeucもあります。

漢字のgrepがうまくいかない原因は、このごちゃごちゃな文字コードの組み合わせが原因でしょう。だから、grepでその辺を個別に指定できるようになっていればよいはずです。ですが、なってないんですね、これが。

nkf とか iconv とか使って変換してやればいいのかも知れませんが、grepの場合元のファイル名とのつながりも必要で、まあなんというか、面倒くさいです。

で、カスと言われる前にググってみると、世の中にはlgrepというツールがあるみたいです。厳密には lv というビューワーをlgrepという名前で呼び出すと、grepと同じ書式で結果を出力してくれるらしく。lgrepには文字コードを個別に指定するオプションがあるので、これがちゃんと使えれば、たぶん、問題は解決します。

で、解決しました。ほぼ。

まず、lv は CygWinに含まれているので、setupでインストールするようにしてやるだけでオッケー牧場でした。(うちの環境は随分前にsetupしたものだったので、他のプログラムのアップデートが同時に山ほど行なわれてえらい時間が掛かってしまいましたがそれは別の話)

次に、lgrep を shell-mode から使う場合は下記のように指定すればよいみたいです。

lgrep -Ku -Ou -n 文字列 ファイル名

-Kはキーボード入力の文字コード、-Oは出力に使う文字コードの指定です。入力ファイルの文字コードは自動で判定してくれるようですね。さりげなく賢いです。

さて本題。

M-x grep で手軽に使えるようにするには、grep-command 変数をカスタマイズします。CUSTOMIZEでやったら.emacs.el に下記のようなコードが出ていました。

(custom-set-variables  
….
‘(grep-command “lgrep -Ku -Ou -n “)
 ‘(grep-find-command “find . -type f -exec lgrep -Ku -Ou -n  {} /dev/nul \\;”)
 ‘(grep-use-null-device t)
….
)

M-x grep-find でも使いたいのでそちら用の変数grep-find-commandもカスタマイズしています。grep-use-null-device を t にしているのは、lgrepは-Hコマンドに非対応のようで(ていうか、-Hは別の意味の別のオプション)、ファイルが一個しか指定されない時にファイル名が出力されないからです。grep-use-null-device を t にしておけば、M-x grep が発行する実際のコマンドラインの末尾にnull-device変数の文字列をくっつけてくれます。

また、grep-findではgrep-use-null-deviceの指定は効かないので、なんかいまいちですが、自分で入れておきます。

もう一つ、CUSTOMIZEではうまく指定できないものに、前述の null-device 変数があります。これはCygWin環境の場合 “/dev/nul” にしてやる必要があるのですけど、NTEmacsの場合はどこかで “NUL” が決め打ちでセットされていて、CMD.EXEを使う時はそれでいいんでしょうけどbashを使う時には適当なタイミングで再設定してやる必要があります。

うちではbashを使う設定をしている場所でやっています。
(bashを使うためのおまじないと一緒に載せておきます。)

(setq explicit-shell-file-name “bash.exe”)
(setq shell-file-name “sh.exe”)
(setq shell-command-switch “-c”)
(setq null-device “/dev/nul”)

さて、これで設定はおしまい。これで概ねうまく動くんですが、“概ね”とか“ほぼ”とか書いてるのは何故かというと、lgrep.exeが時々落ちるんですね、これが (笑)

同じパラメータで再度指定するとうまく動いたりしますからたぶん lgrep のバグだと思うんですが、大分前からバージョンアップされてないみたいだし、ソースは公開されてるとは言っても自分で直すのはたぶん大変だろうしで、まあそんなに頻繁に落ちる訳じゃ無いから当面これでいいかなと (笑)

どういうパターンで落ちやすいのかはこれから使っていくうちにおいおい見えてくると思いますが、最初に食らったのは shift-jis のファイルを読み込ませた時でした。自動判定の問題かなと思って -Is 指定を追加したらうまくいったんですが、その後 -Is を取ってもうまくいくんですよね。初期化されてない変数があるとか、その類のバグかも知れません。

ともあれ、しばらくはこれでいってみる積もりです。