咱們時常會與操做系統交互或在 Ruby 中執行 Shell 命令。Ruby爲咱們提供了完成該任務的諸多方法。html
Execshell
Kernel#exec
經過執行給定的命令來替換當前進程,例如:ruby
$ irb >> exec 'echo "hello $HOSTNAME"' hello codefun $
注意 exec
利用 echo
命令替換了 irb
進程,而後退出。由於 Ruby 實際上結束了該方法,因此只能有限使用。該方法的缺點是,你沒法從 Ruby 腳本中知道命令是執行成功仍是失敗。ui
System操作系統
system
命令與 exec
操做類似,但它是在 subshell 中執行,而不是替換當前進程。與 exec
相比,system
給咱們更多的信息。若是命令執行成功,它返回 true;不然返回 false。翻譯
$irb >> system 'echo "hello $HOSTNAME"' hello codefun => true >> system 'false' => false >> puts $? 256 => nil >>
system
將進程的退出狀態設置到全局變量 $?
。注意 false
命令的退出狀態,老是非 0 值。檢查退出碼讓咱們既能夠拋出(raise)異常,又可以重試(retry)命令。code
新手注意:Unix 命令執行成功退出碼爲 0,不然爲非 0。htm
若是咱們想知道「命令是否執行成功呢?」,使用 system
就很好。然而,咱們時常想要捕獲命令的輸出,並在程序中使用。對象
Backticks (`)進程
backticks(也叫「backquotes」)在 subshell 中執行命令,並從該命令返回標準輸出。
$ irb >> today = `date` => "Wed Jul 4 22:03:15 CST 2012\n" >> $? => #<Process::Status: pid 6169 exit 0> >> $?.to_i => 0
這也許是在 subshell 中執行命令最廣爲人知的方法。如你所見,它返回了命令的輸出,而後咱們能夠像其餘字符串同樣使用它。
注意 $?
並不是是返回狀態的整數,而實際是 Process::Status 對象。咱們不只獲得了退出狀態,並且有進程 ID。Process::Status#to_i
返回整數型的退出狀態(#to_s
返回字符串型的退出狀態)。
使用 backticks 咱們只能得到命令的標準輸出(stdout),而不能得到其標準錯 誤(stderr)。在下面的例子中,咱們執行 Perl 腳原本輸出字符串到標準錯誤。
$ irb >> warning = `perl -e "warn 'dust in the wind'"` dust in the wind at -e line 1. => "" >> puts warning => nil
注意變量 warning 沒有被設置。當咱們在 Perl 中執行 warn
時,產生的標準錯誤輸出並無被 backticks 捕獲。
IO#popen
IO#popen
是在子進程中執行命令的另外一種方法。popen
給你更多的控制,子進程的標準輸入和標準輸出都會鏈接到 IO 對象。
$ irb >> IO.popen("date") { |f| puts f.gets } Wed Jul 4 22:02:31 CST 2012 => nil
雖然 IO#popen
不錯,可是當須要這類細分層次的信息時,我一般使用Open3#popen3
。
Open3#popen3
Ruby 標準庫包含 Open3 類。它易用,並能返回標準輸入、標準輸出、以及標準 錯誤。在本例中,讓咱們使用交互命令 dc
。dc 是從標準輸入讀取的逆波計算器(reverse-polish calculator)。咱們先 push 兩個數字和一個操做符到堆棧 中。而後咱們使用 p
來打印輸出結果。下面咱們 push 五、10 及 +,結果標準輸出得到了15。
$ irb >> require 'open3' => true >> stdin, stdout, stderr = Open3.popen3('dc') => [#<IO:fd 6>, #<IO:fd 7>, #<IO:fd 9>, #<Thread:0x816d46c sleep>] >> stdin.puts(5) => nil >> stdin.puts(10) => nil >> stdin.puts("+") => nil >> stdin.puts("p") => nil >> stdout.gets => "15\n"
使用該命令咱們不只能夠讀取命令的輸出,並且也能寫到命令的標準輸入。這允 許咱們靈活地處理與命令的交互。
若是咱們須要,popen3
也將給咱們標準錯誤。
# (irb continued...) >> stdin.puts("asdfasdfasdfasdf") => nil >> stderr.gets => "dc: stack empty\n"
使用popen3 的缺點是 $?
不返回適當的退出狀態。
$ irb >> require 'open3' => true >> stdin, stdout, stderr = Open3.popen3('false') => [#<IO:fd 8>, #<IO:fd 10>, #<IO:fd 12>, #<Thread:0x8297644 sleep>] >> $? => nil >> $?.to_i => 0
0?false 是假定返回非 0 退出狀態。該缺點帶咱們到 Open4。
Open4#popen4
Open4#popen4
是 Ara Howard 建立的 Ruby Gem。它的操做與 open3
類似,例外是咱們能從程序得到退出狀態。popen4
爲 subshell 返回進程 ID,這樣咱們能從等候的進程得到退出狀態。(你須要安裝 open4 gem)
$ irb >> require 'open4' => true >> pid, stdin, stdout, stderr = Open4::popen4 "false" => [17913, #<IO:fd 6>, #<IO:fd 7>, #<IO:fd 9>] >> $? => nil >> pid => 17913 >> ignored, status = Process::waitpid2 pid => [17913, #<Process::Status: pid 17913 exit 1>] >> status.to_i => 256
你也能夠做爲塊來調用 popen4
,它將自動等候退出狀態。
$ irb >> require 'open4' => true >> status = Open4::popen4("false") do |pid, stdin, stdout, stderr| ?> puts "PID #{pid}" >> end PID 18535 => #<Process::Status: pid 18535 exit 1> >> puts status pid 18535 exit 1 => nil
原文來自 tech.natemurray.com
翻譯 dailyrb
許可 CC-by-sa