外部のプログラムにデータを渡して、その結果を得たい。 標準入出力では問題が起こりそうにないが、コマンドライン引数まわりは怪しく思える。 Windows以外の、システムのデフォルトエンコーディングがUTF-8な環境なら何も問題なくイケそうだが、Windowsではどうか。ここではコマンドライン引数について検証する。
こんなのを用意して、
object OuterProcess { def build(commands: List[List[String]]): Option[ProcessBuilder] = { if (commands.nonEmpty) { build(commands.tail) match { case Some(x) => Some(commands.head #| x) case None => Some(commands.head) } } else { None } } def call(commands: List[List[String]]): String = { build(commands) match { case Some(x) => x !! case None => "" } } }
-Dfile.encoding=UTF-8
な設定で以下のテストを実施した。
class OuterProcessTest extends SpecificationWithJUnit { "OuterProcess.call" should { "receive UTF-8 encoded output" in { OuterProcess.call(List( List("cmd", "/c", "type", "text.txt") )) mustEqual("éindʒəl") //success } "pass unicode arguments to a program" in { OuterProcess.call(List( List("cmd", "/c", "echo", "éindʒəl") )) mustEqual("éindʒəl") //fail } "pass unicode arguments to a program" in { OuterProcess.call(List( List("cmd", "/c", "chcp", "65001", "&&", "cmd", "/c", "echo", "éindʒəl") )) mustEqual("éindʒəl") //success } } }
というわけで、引数は正しくUnicodeなまま、対象のプログラムに渡されている。そして、このecho
のように、プログラムがUnicodeな引数を正しく扱えるかどうかは、そのプログラム自体(またはその設定など)に依存するようだ。例えば、Windowsで動くgrepを用意して以下のテストを行う場合、Gowのgrepでは失敗してGnupackのものでは成功する。これは前者がUnicode(マルチバイト全般?)を与えた時にうまく動作せず、後者では問題ないため。
class OuterProcessTest extends SpecificationWithJUnit { "OuterProcess.call" should { "connect programs" in { OuterProcess.call(List( List("cmd", "/c", "chcp", "65001", "&&", "cmd", "/c", "echo", "éindʒəl"), List("grep", "éindʒəl") )) mustEqual("éindʒəl") } } }