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?
source to share
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
source to share
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.
source to share