[英]Thor: run command without capturing stdout or stderr, and fail on error
我正在編寫Thor腳本,以使用其他工具(即運行shell命令)運行一些測試。 我希望命令中的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 之前手動嘗試打印stdout的問題嗎?
我正在使用IO.popen
執行類似的任務,例如: IO.popen([env, *command]) do |io| io.each { |line| puts ">>> #{line}" } end
IO.popen([env, *command]) do |io| io.each { |line| puts ">>> #{line}" } end
IO.popen([env, *command]) do |io| io.each { |line| puts ">>> #{line}" } end
要捕獲stderr,我將其重定向到stdout command = %w(run-my-tests.sh 2>&1)
更新我已經使用Open3::popen3
構造了一個腳本來Open3::popen3
捕獲stdout和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
在我看來,最簡單的方法是運行shell命令,而不是嘗試捕獲stdout或stderr(相反,讓它們在出現時冒泡)是這樣的:
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命令的包裝器一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.