Ruby Freaks Lounge

第8回 Windows版Ruby 1.9で培う危機回避スキル(前編)

この記事を読むのに必要な時間:およそ 3 分

分かりやすい地雷――存在しない機能

Rubyは比較的移植性の高い言語処理系です。つまり,それぞれ異なる環境向けのRubyが存在し,そうした環境間の差異をRubyインタプリタが吸収することによって,それぞれの環境の違いによらず,同一のRubyスクリプトを実行できるかもしれないということになります。実際,簡単なファイル操作や文字列処理といった,Rubyが得意とする分野のスクリプトは,入出力のエンコーディングの取り扱えさえ間違えなければ,WindowsでもUNIXでも共通のスクリプトをほとんど問題なくそのまま実行できます。

fork

しかし,どうしてもWindowsでは実現困難な機能もごく一部ではありますが存在します。その代表例がforkメソッドです。ご存知の通り,forkメソッドは現在実行中のプロセスのコピーを子プロセスとして実行するというものです。しかし,通常必要なのは現在のプロセスのコピーではないので,即座にexecメソッドを呼びだして別のコマンドを実行させる,という使い方が主流となっています。

リスト1 典型的なfork利用例

pid = fork {
  exec "foo"  # コマンドfooを実行
}

これは,コマンドfooをバックグラウンドで実行し,そのプロセスIDを変数pidに格納する,というスクリプトです。しかし,このスクリプトをmswin32版で実行すると,以下のようにNotImplementedError例外が発生します。

図3 mswin32版Rubyでforkを実行した例

in `fork': fork() function is unimplemented on this machine (NotImplementedError)

これは,エラーメッセージで説明されている通り,mswin32版Rubyにはforkメソッドが実装されていないためです。

しかし,Ruby 1.9ではこのようなパターンを実現するためにforkメソッドを使う必要はありません。1.9で追加されたメソッドProcess.spawnが使用できます。

リスト2 Process.spawnで書き換えた例

pid = Process.spawn "foo"  # コマンドfooをバックグラウンドで実行

よって,そもそもほとんどの場合はforkメソッドを使用する必要はなく,Process.spawnメソッドを使えばよい,ということになります。

File.symlink,File.link

また,UNIX環境では多用される機能であり,Windows環境でも同等の機能が存在するにも拘らず,ほとんど利用されていない,というものも存在します。ファイルやディレクトリに対するシンボリックリンクやハードリンクがそうです。実はこの両方がNTFS上であればWindowsでも使用可能なのですが,シンボリックリンクを作成するFile.symlinkメソッドに関しては現時点ではmswin32版Rubyには実装されていません。

図4 File.symlink実行例

図4 File.symlink実行例

実はシンボリックリンクの作成はWindowsのAPIレベルではWindow Vista以降でしかサポートされておらず,また作成には管理者権限が必要だという制限があります。そのため,Ruby上での実装は様子見という段階です。

一方,ハードリンクを作成するFile.linkメソッドに関しては特に問題なく使用できます。

図5 File.link実行例

図5 File.link実行例

そのため,どうしてもシンボリックリンクでなければいけない場面以外はハードリンクの使用を考慮してみるべき,ということになります。

ところで,この例ではファイルの同一性を判定するためにFile.identical?メソッドを使用しています。従来UNIX環境向けのスクリプトでファイルの同一性を判定する場合,File.statの結果のdevおよびinoを比較するという手法が多用されていました。しかし,この手法はmswin32版ではinoが常に0になるためにうまくいきません。File.identical?メソッドであれば環境によらずファイルの同一性を判定できることが期待できます。

まとめ

今回のまとめは以下の通りです。

  • ファイル名に日本語を使うのは避けましょう。
  • 環境に依存した機能については代替手段の有無を確認しましょう。

次回は,もっと困った事例とその対応策を見ていくことにします。

著者プロフィール

中村宇作(なかむらうさく)

某弱小IT企業の技術担当取締役。2000年末よりRubyコミッタ(mswin32,64担当)。 主にWindows関連の対応とバグ取りとバグ埋めをしています。