在同一个shell进程中运行多个命令

时间:2017-06-15 20:41:38

标签: ruby shell

我尝试通过Ruby运行一系列命令,并捕获stdinstdoutstderr和exitstatus。

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命令失败,并且命令未在同一进程中运行。

如何在单个shell进程中执行一系列命令,记录stdinstdoutstderr以及每个命令的exitstatus? < / p>

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

如果您不是必须的话,我强烈建议您不要将多个shell命令链接到一个系统调用中。一个主要的警告是,您无法单独检查链中每个命令的返回码。这导致对命令流的控制不足。例如,如果链中的第一个命令由于任何原因而失败,则无论第一个命令的状态如何,后续命令仍将尝试执行。这可能是不可取的。

我建议将popen功能封装到方法中,然后为要运行的每个命令调用方法。这将允许您在逐个命令的基础上对任何失败的执行做出反应。