2017-09-25 65 views
0

我正在編寫一個Thor腳本來運行來自其他工具的一些測試,即運行shell命令。我希望命令中的stdout和stderr能夠持續流入我的控制檯。Thor:運行命令時未捕獲stdout或stderr,並且出錯失敗

首先嚐試使用反引號,但stdout/stderr自然不會被打印出來(而是在返回值中捕獲stdout)。

desc "mytask", "my description" 
def mytask 
    `run-my-tests.sh` 
end 

我的下一個方法是使用Open3爲:

require "open3" 
desc "mytask", "my description" 
def mytask 
    Open3.popen3("run-my-tests.sh") do |stdin, stdout, stderr| 
    STDOUT.puts(stdout.read()) 
    STDERR.puts(stderr.read()) 
    end 
end 

然而,上述方法將得到stdout和stderr輸出全,只在最後打印。在我的使用案例中,我寧願看到失敗的輸出,並在測試可用時通過測試。

http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html,我看到我們可以通過塊讀取流,即使用gets()而不是read()。例如:

require "open3" 
desc "mytask", "my description" 
def mytask 
    Open3.popen3(command) do |stdin, stdout, stderr| 
    while (out = stdout.gets()) || err = (stderr.gets()) 
     STDOUT.print(out) if out 
     STDERR.print(err) if err 
    end 
    exit_code = wait_thr.value 
    unless exit_code.success? 
     raise "Failure" 
    end 
    end 
end 

它看起來像最好和最乾淨的方法?是否需要手動嘗試在 stderr之前打印標準輸出

+0

您應該使用'IO.select'來監視標準輸出和標準錯誤。 – Stefan

回答

0

我使用IO.popen類似的任務,像這樣: IO.popen([env, *command]) do |io| io.each { |line| puts ">>> #{line}" } end 爲了捕捉標準錯誤我只是把它重定向到stdout command = %w(run-my-tests.sh 2>&1)

更新 我已經構造使用Open3::popen3捕捉到標準輸出腳本和stderr分開。它顯然有很大的空間形式的改進,但基本的想法有希望是明確的。

require 'open3' 

command = 'for i in {1..5}; do echo $i; echo "$i"err >&2; sleep 0.5; done' 
stdin, stdout, stderr, _command_thread = Open3.popen3(command) 

reading_thread = Thread.new do 
    kilobyte = 1024 

    loop do 
    begin 
     stdout.read_nonblock(kilobyte).lines { |line| puts "stdout >>> #{line}" } 
     stderr.read_nonblock(kilobyte).lines { |line| puts "stderr >>> #{line}" } 
    rescue IO::EAGAINWaitReadable 
     next 
    rescue EOFError 
     break 
    end 

    sleep 1 
    end 
end 

reading_thread.join 
stdin.close 
stdout.close 
stderr.close 
+0

我們發現stdout和stderr之間的區別很有用,但也可以在打印到控制檯時一起讀取它們。即不會犧牲有一個正確的stderr流:( – jleeothon

0

我看來,像運行shell命令的最簡單方法和嘗試捕捉標準輸出或標準錯誤(代替,讓他們泡了,因爲他們來)是這樣的:

def run *args, **options 
    pid = spawn(*args, options) 
    pid, status = Process.wait2(pid) 
    exit(status.exitstatus) unless status.success? 
end 

反引號或system()的問題是前者捕獲stdout,而後者僅返回命令是否成功。 spawn()system()的更多信息選擇。我寧願讓我的Thor腳本工具失敗,就好像它只是這些shell命令的包裝一樣。

相關問題