2017-06-15 124 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

相关问题