対象:
JRuby

JavaのRuntime.execを利用して外部コマンドを実行

RubyあるいはJRubyにおいてLinuxのコマンドを実行する場合、IO.popen、system、exec、及び`(バッククォート)で括る等がある。しかし、JRubyでは日本語を使用したパラメータ等がうまく渡らなかったりする場合がある。そのような場合、JavaのRuntime.execを利用してみるのも手だ。

# ワイルドカードと日本語のキーワードを含むコマンドの実行
require "java"

$KCODE = "UTF8"

cmds = ["/bin/sh", "-c", "grep 日本語 *.rb"]
# cmdsをRuntime.execに渡す際、JavaのString配列へ変換
proc = java.lang.Runtime.runtime.exec(cmds.to_java(:string))
p "proc is #{proc.java_class}"
# JavaのInputStreamをRubyのIOへ変換
io = Java.java_to_ruby(org.jruby.RubyIO.new(JRuby.runtime, proc.input_stream).java_object)
p "io is #{io.class}"
# 通常のIOとして処理
while io.gets
  p $_
end

しかし、Linux環境において単純にRuntime.execでコマンドを実行すると、shellを介さないためワイルドカードが展開されない。そこで、String配列を渡す形式のRuntime.execで、/bin/sh -cとともに任意のコマンドを渡して実行する。

この際に問題になるのがRuntime.execへJava配列を渡さなければならないことである。Ruby配列のままRuntime.execへ引数を渡そうとすると以下のエラーに遭遇することになる。

java_exec_test.rb:8: no exec with arguments matching [class org.jruby.RubyArray] on object # (NameError)

通常の用途では、特にオブジェクトのJava-Ruby相互変換を意識する必要はないのだが、この場合はRuby配列をto_java(:string)メソッドで明示的にJava配列に変換して渡す必要がある。

また、Runtime.execの結果として得られるJavaのProcessオブジェクトをそのままJava的に操作しても良いのだが、上記のコードではProcessから得られるInputStreamをRubyのIOオブジェクトに変換してRubyらしい処理を行っている。

(2010/02/20)

新着情報
【オープンソースソフトウェア環境構築】Apple silicon Macで開発環境を構築
【Rust Tips】Actix webでJSONをPOSTする
【Rust Tips】コマンドライン引数を取得する

Copyright(C) 2004-2014 モバイル開発系(K) All rights reserved.
[Home]