2017-06-15 273 views
3

我試圖通過Ruby運行一系列命令,並捕獲stdin,stdout,和exitstatus。在同一個shell進程中運行多個命令

require "open3" 
require "pp" 

command_list = [ 
    "export MY_ENV_VAR=foobar", 
    "printenv MY_ENV_VAR" 
] 

executed_commands = [] 
result = nil 

command_list.each do |command| 
    stdout, stderr, status = Open3.capture3(command) 
    result = status.exitstatus 
    executed_commands << [command, stdout, stderr, result] 
    break if result != 0 
end 

pp executed_commands 
puts "exited with #{result} exit status." 

該過程退出具有非零狀態,表明該命令printenv MY_ENV_VAR失敗,並且這些命令不被在同一進程中運行。

如何可以在一個單一的外殼進程執行的一系列命令,記錄stdinstdoutstderr和每個命令的退出狀態?

回答

2

用於運行一系列命令的代碼很好。問題在於你錯誤地設置了環境變量。子進程不能像你想要做的那樣設置父進程的環境。子進程做繼承其父的環境,所以這裏是修復你的代碼的一種方法:

require "open3" 
require "pp" 

ENV['MY_ENV_VAR'] = 'hi' 

command_list = [ 
    "printenv MY_ENV_VAR" 
] 

executed_commands = [] 
result = nil 

command_list.each do |command| 
    stdout, stderr, status = Open3.capture3(command) 
    result = status.exitstatus 
    executed_commands << [command, stdout, stderr, result] 
    break if result != 0 
end 

pp executed_commands 
puts "exited with #{result} exit status." 

結果,當我使用Ruby 2.3.1在Linux上運行是這樣的:

[["printenv MY_ENV_VAR", "hi\n", "", 0]] 
exited with 0 exit status. 

現在如果你想傳遞一個環境變量設置爲子進程,而無需修改自己的進程的環境,看到的Open3.capture3參數的文檔:

https://ruby-doc.org/stdlib/libdoc/open3/rdoc/Open3.html#method-c-capture3

+0

我將如何創建一個父shell進程,然後在該shell中執行一系列命令? – Richard

+2

你可以試着把多個命令放在一個字符串中,並用'&&'或';'分隔它們。我建議前者,因爲只要出現錯誤就會停止。 –

2

我強烈建議您不要將多個shell命令鏈接到一個系統調用中,如果您沒有必要的話。一個重要的警告是你不能單獨檢查鏈中每個命令的返回代碼。這導致對命令流程缺乏控制。例如,如果鏈中的第一個命令因任何原因失敗,則後續命令仍會嘗試執行,而不管第一個命令的狀態如何。這可能是不可取的。

我建議將popen功能封裝到一個方法中,並且只是爲每個要運行的命令調用方法。這將允許您對每個命令執行失敗做出反應。

+0

在一次調用中運行多個命令時,雖然不能單獨檢查返回代碼,但可以通過用'&&而不是';'加入命令來避免繼續失敗的問題。 –

+1

這是真的。作爲一個經驗法則,我會更加輕鬆地處理這個問題。同樣,如果你沒有嚴格的技術理由來組合命令,請避免它。此外,這種方法還有安全隱患,但這不在這個問題的範圍之內。 – Jakir00

相關問題