我正在编写一个函数来执行shell命令,并返回它的退出代码STDOUT和STDERR。
问题是,此函数无法正确捕获STDOUT和STDERR输出。
def sh(*args)
options = args[-1].respond_to?(:to_hash) ? args.pop.to_hash: {}
options = { :timeout => 0, :sudo => false }.merge(options)
cmd = options[:sudo] == false ? args[0] : "sudo " << args[0]
begin
stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
pid = wait_thr[:pid]
out_buf = ""
err_buf = ""
start = Time.now
# Manually ping the process per 0.2 second to check whether the process is alive or not
begin
out_buf << stdout.read_nonblock(4096)
err_buf << stderr.read_nonblock(4096)
# kill the process if it timeouts
if options[:timeout] != 0 && (Time.now - start) > options[:timeout]
Process.kill("KILL", pid)
Process.detach(pid)
raise RuntimeError, "process with pid #{pid} timed out with #{options[:timeout]} seconds."
end
sleep 0.2
rescue IO::WaitReadable, EOFError
end while wait_thr.alive?
rescue => e
NtfLogger.warn("sh '#{args}' executed with failure: #{e}")
ensure
if wait_thr.nil?
return 1, out_buf, err_buf
else
return wait_thr.value.exitstatus, out_buf, err_buf
end
end
end # end of sh有人能帮我找出问题出在哪里吗?
发布于 2013-11-25 13:25:05
我对popen3文档的理解是,最好在块中进行处理:
Open3.popen3([env,] cmd... [, opts]) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
end在非块形式中,文档注意到流必须关闭:
stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts])
pid = wait_thr[:pid] # pid of the started process.
...
stdin.close # stdin, stdout and stderr should be closed explicitly in this form.
stdout.close
stderr.close
exit_status = wait_thr.value # Process::Status object returned.http://www.ruby-doc.org/stdlib-2.0.0/libdoc/open3/rdoc/Open3.html#method-c-popen3
最后,顺便说一句,这里有一个围绕capture3的包装器,我在我的一端使用它。如果sh实用程序中与线程相关的部分并不重要,您可以很容易地将其扩展为添加一个sudo选项:
#
# Identical to Open3.capture3, except that it rescues runtime errors
#
# @param env optional (as `Kernel.system')
# @param *cmd the command and its (auto-escaped) arguments
# @param opts optional a hash of options (as `Kernel.system')
#
# @return [stdout, stderr, success] | [$/, $/, nil] on error
#
def system3(*cmd)
begin
stdout, stderr, status = Open3.capture3(*cmd)
[stdout, stderr, status.success?]
rescue
[$/, $/, nil]
end
endhttps://stackoverflow.com/questions/20184731
复制相似问题