#IO.popen
では標準出力しか取得出来ない?
Q. FFmpeg や rtmpdump ではログが標準エラー出力に出力されます。IO.popen
の使い方をググったときに見たのですが、標準出力しか取得出来なさそう。これらのコマンドのログを利用したいときにはその他の手段を使わないとダメなんでしょうね。
A. いいえ、そんなことはありません。標準エラー出力も取得出来ます1。
IO.popen
の普段の使い方(オプションなし)だと標準出力しか取得出来ないのですが、オプションで指定すると標準エラー出力を取得出来ます。
IO.popen(command, :err => [:child, :out])
IO.popen(command, :err => [:child, :out]) { |pipe| ... }
なお、ブロックパラメータ pipe
は IO
インスタンスなので、文字出力として扱う場合には、さらに IO#each_line
や IO#each_char
で扱いましょう。
標準エラー出力を扱う場合には Open3
ライブラリを使うことが多いようですが、わざわざ require 'open3'
しなくても IO.popen
ですむのであれば、そのほうが簡単でいいのではないでしょうか。
#ファイルディスクリプタの書き方
ファイルデスクリプタを表すためには、以下が利用できます。
:in
- 標準入力, ファイルデスクリプタ0
:out
- 標準出力, ファイルデスクリプタ1
:err
- 標準エラー出力, ファイルデスクリプタ2
整数
- 指定した整数が表すファイルデスクリプタ
IO
-IO#fileno
で表されるファイルデスクリプタ
module function Kernel.#spawn (Ruby 2.2.0)
なので、以下のどれであっても同じ意味です。理解しやすいものであればどれでもいいのではないでしょうか。
IO.popen(command, :err => [:child, :out]) { |pipe| ... }
IO.popen(command, err: [:child, :out]) { |pipe| ... }
IO.popen(command, 2 => [:child, 1]) { |pipe| ... }
IO.popen(command, $stderr => [:child, $stdout]) { |pipe| ... }
IO.popen(command, STDERR=> [:child, STDOUT]) { |pipe| ... }
#おまけ:IO.popen
のオプションで便利そうなもの
以下の引用では Kernel.#spawn
での解説ですが、IO.popen
でも使えます。
「:chdir」で子プロセスのカレントディレクトリを変更できます。
pid = spawn(command, :chdir=>"/var/tmp")
「:umask」で子プロセスの umask を指定できます。
>```rb
pid = spawn(command, :umask=>077)
#感想
IO
クラス(や File
クラス)は奥が深い。
#詳細情報へのリンク
この記事は IO.popenメソッドで標準エラー出力を取得するには - 別館 子子子子子子(ねこのここねこ) の要約です。
-
Ruby 1.9以降対応。もう1.8系を使ってるひとは居ないでしょうけど。 ↩