Windows上でRubyを使うときの話です。
先日、メインマシンで使うコマンドラインツールを極力MSYS2でインストールするようにしたのだが、その結果、日本語を含むファイル名を扱う一部のRubyスクリプトが動かなくなった。
結論から言うと、MSYS2のRubyでファイル名を指定する場合は、スクリプトのエンコーディングに関わらずUTF-8のものを指定しないと、ファイル名を正常に認識できない模様。
例を以下に挙げる。
#!/usr/bin/env ruby
# -*- coding: Windows-31J -*-
puts File.readlines('てすと.txt').size
「てすと.txt」というファイルの行数を出力するだけのスクリプトである。ここでスクリプト2行目にある通り、スクリプトの文字コードはShift_JISで保存しているものとする(なぜWindows-31Jと書くのかについては、例えばこの記事を参照)。
このスクリプトを動かすと、まずRubyの2.3.0p0 x64-mingw32版(RubyInstaller for Windowsで公開されているもの)では
>cat てすと.txt
foo
bar
buz
>ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x64-mingw32]
>ruby filename.rb
3
と意図した通り動いてくれるのだが、Rubyの2.3.0p0 x86_64-msys版(MSYS2のpacmanでインストールできるもの)では
>ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-msys]
>ruby filename.rb
filename.rb:3:in `readlines': No such file or directory @ rb_sysopen - ▒Ă▒▒▒.txt (Errno::ENOENT)
と、シフトJISで書かれたファイル名を正しく認識してくれないのである。
なお、スクリプトを以下のように修正したらx64-mingw32版、x86_64-msys版ともに問題なく動いた。なのでおそらく、MSYS2のファイル処理APIの仕様の違いなのだろうなあ。
#!/usr/bin/env ruby
# -*- coding: Windows-31J -*-
puts File.readlines('てすと.txt'.encode('utf-8')).size
# ファイル名についてはUTF-8にしたものを使う