2011-06-14 44 views
312

是什麼以下Ruby方法之間的差異的差異?紅寶石,EXEC,系統和%×()或反引號

execsystem%x()反引號

我知道他們是用來執行終端通過紅寶石的命令編程,但我想知道爲什麼有三種不同的方法來做到這一點。

+5

因爲有人剛挖出了這個古老的線程,「使用UNIX進程」是Ruby開發者一個很好的書感興趣的話題:http://workingwithunixprocesses.com/ – 2012-06-24 09:30:59

+0

有一個偉大的Ruby關於該主題的Quicktips文章:[執行shell命令](http://rubyquicktips.com/post/5862861056/execute-shell-commands)。 – 2011-06-14 04:51:15

+1

這些命令和其他許多命令在文檔中有相當好的解釋:[exec](http://www.ruby-doc.org/core/Kernel.html#method-i-exec)[system](http: //www.ruby-doc.org/core/Kernel.html#method-i-system)[backticks](http://www.ruby-doc.org/core/Kernel.html#method-i-60) – zetetic 2011-06-14 04:18:58

回答

339

系統

system方法調用的系​​統程序。您必須將此命令作爲字符串參數提供給此方法。例如:

>> system("date") 
Wed Sep 4 22:03:44 CEST 2013 
=> true 

調用程序會使用你的Ruby程序的當前STDINSTDOUTSTDERR對象。事實上,實際的回報值是truefalsenil。在該示例中,通過STDIN的IO對象打印日期。該方法將返回true如果該進程具有零個狀態退出,false如果進程與非零狀態和nil退出,如果執行失敗。

另一個副作用是,全局變量$?被設定爲Process::Status對象。該對象將包含有關調用本身的信息,包括調用的進程的進程標識符(PID)和退出狀態。

>> system("date") 
Wed Sep 4 22:11:02 CEST 2013 
=> true 
>> $? 
=> #<Process::Status: pid 15470 exit 0> 

反引號

Backticks(``)調用的系統程序,並返回它的輸出。與第一種方法相反,命令不是通過字符串提供的,而是通過將其放入反引號對中。

>> `date` 
=> Wed Sep 4 22:22:51 CEST 2013 

全局變量$?也是通過反引號設置的。反引號你也可以使用字符串插值。

%×()

使用%x是將反引號樣式的替代方案。它也會返回輸出。像它的親屬%w%q(等等),只要括號式分隔符匹配,任何分隔符就足夠了。這意味着%x(date),%x{date}%x-date-都是同義詞。像反引號%x可以利用字符串插值。

EXEC

通過使用Kernel#exec當前進程(你的Ruby腳本)時,可以通過調用exec過程。該方法可以採用一個字符串作爲參數。在這種情況下,字符串將受shell擴展。當使用多個參數時,第一個參數用於執行一個程序,並且提供以下參數作爲要調用的程序的參數。

Open3.popen3

有時需要的信息寫入標準輸入或標準錯誤,你需要對這些得到控制,以及。這裏Open3.popen3就派上用場了:

require 'open3' 

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread| 
    pid = thread.pid 
    puts stdout.read.chomp 
end 
+1

爲了更細緻地控制調用如何處理'STDIN','STDOUT','STDERR',請考慮'Open3.popen3';例如請參閱http://stackoverflow.com/a/10922097/258662 – cboettig 2014-04-12 20:46:52

+1

@platzhirsch - 非常好解釋。謝謝。 – itsh 2015-08-26 15:59:34

+0

謝謝,補充。 @cboettig – 2016-09-20 14:09:06

91

他們做不同的事情。 exec用新進程替換當前進程,從不返回system調用另一過程和其退出值返回到當前進程。使用反引號調用另一個進程,將該進程的輸出返回到當前進程。

176

下面是基於this answer的流程圖。另請參閱using script to emulate a terminal

enter image description here

+1

這並不是那麼簡單。在我的情況下,「可以(並且需要)阻塞,直到過程完成」,然後使用popen3來檢查STDOUT/STDERR輸出。 – Nakilon 2016-09-25 03:06:24

+0

您可以通過在while循環中封裝它來始終導致非阻塞呼叫(有效)阻塞。您無法輕鬆地將阻塞呼叫轉換爲非阻塞呼叫。 – Ian 2016-10-05 12:31:04