ようこそゲストさん

色々日記(ざ・めも)

メッセージ欄

2013年2月の日記

一覧で表示する

2013/02/21(木) RubyでUTF-8ファイル名&外部コマンド実行

2013/02/21 16:33 PC(プログラミング)
Rubyの``やsystemで外部コマンド実行するときに、実行ファイル自体や引数にUTF-8文字(SJISマッピング無し)が渡せないのであれこれ悩んだ問題。

確認はWindows7 64bit & Ruby1.9.3p0(ActiveScriptRuby)

前提。WindowsはファイルシステムがNTFSならUTF-8ファイル名を命名できる。内部コードもUTF-8になっている(はず)。しかし古いAPIを触ったり、INPUT/OUTPUT周りを見るとまだShiftJIS(Windows-31J)が多い。このズレは厄介で、ハマりどころのA代表。特にRubyの場合、UNIX寄りでWindows特有処理のケアはやっぱり甘い…

閑話休題。Windows&UTF-8の扱いが比較的良くなっているRuby1.9系(Dir.globの引数に.encode('utf-8')などでUTF-8文字列を渡すとUTF-8ファイル名が取れる)でも、マジックコメント入れてUTF-8保存しただけだと外部実行が出来ない。
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-

`utf8_filename`
どうにも通らない。SJISマッピング出来るファイルなら、SJISでやればいいだけの話なのだがUTF-8にあってSJISにない文字(U+2661(はーと)とか)が混ざってると動かない。


で、とりあえず色々やってみたのだが、結論から言うと綺麗に書くのは諦めた。

ちゃんと調べるべきなのだが(やってない)、どうもRubyが叩いてるAPI自体が古いんじゃないかという。

unicode - Ruby system() doesn't accept UTF-8? - Stack Overflow

なので、苦肉の策。
バッチファイルを作成して、それを実行する。
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-

open("tmp.bat", "w"){ |fp|
	fp.write("chcp 65001\n")
	fp.write("utf8_filename\n")
}

out = `tmp.bat`
Windowsのバッチ実行ではコードページが合えば、UTF-8ファイル名も通るのでそれを利用する。引数にファイル名を指定するときも同様。\\の数とかダブルクオート囲いとか先頭に./が必要な場合は適切にすること。

うーん、汚すぎて死にそう。

[参考]
Rubyで外部コマンドを実行して結果を受け取る方法あれこれ #Ruby - Qiita

systemuは知らなかった。