Run a command line with custom environment

2020-03-01 07:24发布

问题:

In Ruby, I want to be able to:

  1. run a command line (via shell)
  2. capture both stdout and stderr (preferably as single stream) without using >2&1 (which fails for some commands here)
  3. run with additional enviornment variables (without modifying the environment of the ruby program itself)

I learned that Open3 allows me to do 1 and 2.

              cmd = 'a_prog --arg ... --arg2 ...'
              Open3.popen3("#{cmd}") { |i,o,e|
                output = o.read()
                error = e.read()
                # FIXME: don't want to *separate out* stderr like this
                repr = "$ #{cmd}\n#{output}"
              }

I also learned that popen allows you to pass an environment but not when specifying the commandline.

How do I write code that does all the three?

...

Put differently, what is the Ruby equivalent of the following Python code?

>>> import os, subprocess
>>> env = os.environ.copy()
>>> env['MYVAR'] = 'a_value'
>>> subprocess.check_output('ls -l /notexist', env=env, stderr=subprocess.STDOUT, shell=True)

回答1:

Open.popen3 optionally accepts a hash as the first argument (in which case your command would be the second argument:

cmd = 'a_prog --arg ... --arg2 ...'
Open3.popen3({"MYVAR" => "a_value"}, "#{cmd}") { |i,o,e|
  output = o.read()
  error = e.read()
  # FIXME: don't want to *separate out* stderr like this
  repr = "$ #{cmd}\n#{output}"
}

Open uses Process.spawn to start the command, so you can look at the documentation for Process.spawn to see all of it's options.