RubyでLinux shellコマンドを実行する6つの方法の詳細

5239 ワード

Rubyではshellコマンドを実行するのはおかしくありません.Rubyは開発者が実現するために約6つの方法を提供しています.これらの方法は簡単ですが、Rubyスクリプトで端末コマンドを呼び出す方法について具体的に説明します.
exec
execは、指定したコマンドを現在のプロセスの操作に置き換え、指定したコマンドが終了するとプロセスが終了します.
 
  
exec 'echo "hello world"'
print 'abc'

上記のコマンドを実行すると、abcの出力がなく、echo「hello world」コマンドを実行するとプロセスが終了することがわかります.後続のprint'abc'は実行されません.
 
  
ruby testCommand.rb
hello world

execを使用すると、shellコマンドの実行が成功したか失敗したかを知ることができません.
system
Systemはexecと似ていますが、systemが実行するコマンドは現在のプロセスではなく、新しく作成されたプロセスです.システムは、コマンドの実行結果が成功したか失敗したかを示すブール値を返します.
 
  
$ irb
> system 'echo "hello $HOSTNAME"'
hello androidyue
 => true
> puts $?
pid 11845 exit 0
 => nil
> system 'false'
 => false
> puts $?
pid 11858 exit 1
 => nil
>>

システムはプロセスの終了したステータスコードを$に割り当てます.プログラムが正常に終了したら、$?を選択します.終了したステータスコードを検出することでrubyスクリプトに異常を投げ出したり、再試行したりすることができます.
注意:Unix-likeシステムでは、プロセスの終了ステータスコードは0と0で表され、0は成功、0は失敗を表します.
システムは、コマンドの実行が成功したか失敗したかを教えてくれますが、実行コマンドの出力を得てスクリプトで使用する必要がある場合があります.システムが直接満足できないのは明らかで、逆引用符を使って実現する必要があります.
逆引用符(`)
逆引用符を使用することはshellでよく使われるコマンド出力内容を取得する方法であり、rubyでも可能であり、少しも変更する必要があります.逆引用符を使用してコマンドを実行すると、コマンドは別のプロセスで実行されます.
 
  
1.9.3p448 :013 > today = `date`
 => "Sat Nov 15 19:28:55 CST 2014
"
1.9.3p448 :014 > $?
 => #<:status: pid="" exit="">
1.9.3p448 :015 > $?.to_i
 => 0
1.9.3p448 :016 >

上記の方法はこのように簡単で、返される文字列の結果を直接操作することができます.
注意、$?もはや上記のような単純な脱退状態コードではなく,実際にはProcess::Statusオブジェクトである.プロセスの終了ステータスコードだけでなく,プロセスのIDも知ることができる.$を使う?to_i終了したステータスコードが得られ、$を使用します.to_sはプロセスid,終了ステータスコードなどの情報を含む文字列を得る.
逆引用符を使用した結果、次の例では、エラー文字列を出力するperlスクリプトを実行するなど、標準的な出力(stdout)しか得られず、標準的なエラー情報(stderr)は得られません.
 
  
 $ irb
  >> warning = `perl -e "warn 'dust in the wind'"`
  dust in the wind at -e line 1.
  => ""
  >> puts warning

  => nil


warningはエラーの情報を得ていないことがわかり、これは反引用符が標準エラーの情報を得ることができないことを示している.
IO#popen
IO#popenもコマンドを実行する方法であり、そのコマンドも別のプロセスで実行される.popenを使用すると、IOオブジェクトを操作するように標準入力と出力を処理できます.
 
  
$ irb
>> IO.popen("date") { |f| puts f.gets }
Mon Mar 12 18:58:56 PDT 2007
=> nil

Open3#popen3
標準のRubyライブラリにはOpen 3も用意されています.このクラスを使用すると、標準入力、出力、エラーを簡単に処理できます.ここではインタラクティブなツールdcを使用します.dcは逆ポーランド式(接尾辞式とも呼ばれ、各演算子が演算対象の後に置かれる)の計算機で、標準入力から数学式を読み取ることをサポートします.この例では,2つの数値と1つのオペレータをスタック処理する.次にpを用いて結果を出力する.例えば、5と10を入力し、+を入力すると、15の出力が得られます.
 
  
$ irb
  >> stdin, stdout, stderr = Open3.popen3('dc')
  => [#<0x6e5474>, #<0x6e5438>, #<0x6e53d4>]
  >> stdin.puts(5)
  => nil
  >> stdin.puts(10)
  => nil
  >> stdin.puts("+")
  => nil
  >> stdin.puts("p")
  => nil
  >> stdout.gets
  => "15
"
0x6e53d4>0x6e5438>0x6e5474>

この方法では,コマンドの出力だけでなく,コマンドの入力操作も読み取ることができる.この方法はインタラクティブな操作に便利である.popen 3により,標準的なエラー情報も得ることができる.
 
  
  # (irb continued...)
  >> stdin.puts("asdfasdfasdfasdf")
  => nil
  >> stderr.gets
  => "dc: stack empty
"

しかし、ruby 1.8.5ではpopen 3に欠陥があり、プロセスの終了状態は$に書き込まれていません.に表示されます.
 
  
$ irb
  >> require "open3"
  => true
  >> stdin, stdout, stderr = Open3.popen3('false')
  => [#<0x6f39c0>, #<0x6f3984>, #<0x6f3920>]
  >> $?
  => #<:status: pid="26285,exited(0)">
  >> $?.to_i
  => 0
0x6f3920>0x6f3984>0x6f39c0>

なぜ0なのか、falseコマンドの実行後の終了状態は0ではないはずですが、この欠陥のため、Open 4を理解する必要があります.
Open4#popen4
Open 4#popen 4は、Open 3#popen 3とあまり差がなく、プログラムの終了状態も得ることができます.popen 4はまた、サブプロセスIDを返すこともできる.プロセス終了状態は、プロセス::waitpid 2に対応するプロセスIDを付けて取得することもできます.ただしopen 4のgemをインストールすることが前提です.
 
  
$ irb
  >> require "open4"
  => true
  >> pid, stdin, stdout, stderr = Open4::popen4 "false"
  => [26327, #<0x6dff24>, #<0x6dfee8>, #<0x6dfe84>]
  >> $?
  => nil
  >> pid
  => 26327
  >> ignored, status = Process::waitpid2 pid
  => [26327, #<:status: pid="26327,exited(1)">]
  >> status.to_i
  => 256
0x6dfe84>0x6dfee8>0x6dff24>