環境
- ruby 2.5
やりたいこと
Rubyでは様々な方法でコマンドを実行できるが、1番シンプルなのはバッククオートを使う方法だと思う
p `date` # dateコマンドを実行
これは本当に楽なのだが、欠点が一つあって標準出力は取れるが、標準エラー出力、さらに結果のstatusが取れない。したがってそのコマンドが正常に終了したかどうかはバッククオートのやり方ではわからない
そこでsystemuのライブラリ入れたりなんやかんややってたが、実は標準ライブラリで実現できた
やりかた
open3という標準ライブラリを使う。
require 'open3' cmd = "mkdir /tmp/hoge" stdout, stderr, status = Open3.capture3(cmd) p stdout p stderr p status
これで
- stdoutに標準出力
- stderrに標準エラー出力
- statusにプロセスの終了ステータス
が入る
以下は正常に終了した例
"" "" #<Process::Status: pid 30477 exit 0>
以下は失敗した例
"" "mkdir: /tmp/hoge: File exists\n" #<Process::Status: pid 30540 exit 1>
蛇足
ちなみにruby2.6以降だが、system()で外部コマンドを実行する際にexception:true
を渡すとプロセス終了ステータスが異常だった場合に例外が投げられる
cmd = "mkdir /tmp/hoge" system(cmd, exception: true)
結果
$ruby a.rb mkdir: /tmp/hoge: File exists Traceback (most recent call last): 1: from a.rb:6:in `<main>' a.rb:6:in `system': Command failed with exit 1: mkdir (RuntimeError)
もちろんcatchすることも可能。が、標準エラー出力を取得することはできないっぽい?
cmd = "mkdir /tmp/hoge" begin system(cmd, exception: true) rescue => e puts e.class puts e.message end
結果
$ ruby a.rb mkdir: /tmp/hoge: File exists RuntimeError Command failed with exit 1: mkdir