Open3.capture() をつかえば、外部コマンド実行結果の stdout, stderr, 実行ステータスは得られる。
しかし コマンド実行で stdout, stderr に大量に出力される可能性がある場合、この方法ではメモリーを圧迫してしまう危険がある。
そこで、出力結果をメモリーに展開せずに、 stdout, stderr を得る方法を検討してみた。
発想としては、
- system() を使う。system() の return 値で実行ステータスを判定する。
- stdout, stderr はファイルにリダイレクトする。必要に応じて、ファイルの中身を参照する。
以下にコードを書いてみた。 ( ruby 1.9.3-p484)
このコード例では、 system() の return 値は 常に true か falseになる。
( リダイレクトをしないなら、 該当コマンドが無い時などは nil が返るのだが )
このコード例では、該当コマンドが無い時は、false が返り、stderr に "command not found" が記録される。
call_system.rb
def call_system(command)
stdout_txt = 'stdout.txt'
stderr_txt = 'stderr.txt'
ret = system "#{command} 2> #{stderr_txt} 1> #{stdout_txt}"
if ret
puts "# --- success [#{command}]"
else
puts "# --- error [#{command}]"
end
puts "# --- srdout: #{`wc -l #{stdout_txt}`.to_i} line(s), srderr: #{`wc -l #{stderr_txt}`.to_i} line(s)"
end
commands = [
'ls -algt /', # success
'xxxx -algt ~', # error
"ruby -e 'exit 0'", # success
"ruby -e 'exit 1'", # error
"ruby -e 'exit 2'", # error
"ruby -e '100.times{puts \"1\"; warn \"2\\n\"};0'", # success
]
commands.each do |c|
puts '# =========================='
call_system(c)
end
実行結果は次のようになる。
ruby call_system.rb
# ==========================
# --- success [ls -algt /]
# --- srdout: 41 line(s), srderr: 0 line(s)
# ==========================
# --- error [xxxx -algt ~]
# --- srdout: 0 line(s), srderr: 1 line(s)
# ==========================
# --- success [ruby -e 'exit 0']
# --- srdout: 0 line(s), srderr: 0 line(s)
# ==========================
# --- error [ruby -e 'exit 1']
# --- srdout: 0 line(s), srderr: 0 line(s)
# ==========================
# --- error [ruby -e 'exit 2']
# --- srdout: 0 line(s), srderr: 0 line(s)
# ==========================
# --- success [ruby -e '100.times{puts "1"; warn "2\n"};0']
# --- srdout: 100 line(s), srderr: 200 line(s)