Execute multiple commands in the same shell mode

I'm trying to run a series of commands through Ruby and grab stdin

, stdout

, stderr

and 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."

      

This process exits with a nonzero status, indicating that the command printenv MY_ENV_VAR

failed and that the commands are not being executed in the same process.

How can I execute a series of commands in a single process shell, writing stdin

, stdout

, stderr

and exitstatus each team?

+3


source to share


2 answers


Your code for running a series of commands is fine. The problem is that you changed the environment variable incorrectly. The child process cannot establish its parent's environment as you tried to do. Child processes inherit their parent's environment, so here's one way to fix your code:

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."

      

The result when I run this on Linux with Ruby 2.3.1 is:



[["printenv MY_ENV_VAR", "hi\n", "", 0]]
exited with 0 exit status.

      

Now, if you want to pass an environment variable to a child process without changing the process's own environment, see the documentation for the arguments Open3.capture3

:

https://ruby-doc.org/stdlib/libdoc/open3/rdoc/Open3.html#method-c-capture3

+2


source


I would strongly suggest that you do not combine multiple shell commands into a single system call unless you have to. The main caveat is that you cannot individually check the return codes of each command in the chain. This results in a lack of control over the command flow. For example, if the first command in the chain does not work for any reason, subsequent commands will still try to execute regardless of the state of the first command. This may not be desirable.



I suggest to encapsulate the popen functionality into a method and just call the method for each command you want to run. This will allow you to react to any failed command line execution.

+2


source







All Articles