23

I need to shell out to a process while setting an environment variable for it. I tried this one-liner:

system "RBENV_VERSION=system ruby extconf.rb"

This syntax works in shell script but not from ruby. (Update: turns out this syntax works from ruby after all, but I failed to see its effect due to my particular use-case.)

So I'm doing this:

rbenv_version = ENV['RBENV_VERSION']
ENV['RBENV_VERSION'] = 'system'
begin
  system "ruby extconf.rb"
ensure
  ENV['RBENV_VERSION'] = rbenv_version
end

I'm forced to such a long expression because I don't want to override the environment variable permanently if it already had a value.

Anything shorter that comes to your mind?

5 Answers 5

76
system({"MYVAR" => "42"}, "echo $MYVAR")

system accepts any arguments that Process.spawn accepts.

Sign up to request clarification or add additional context in comments.

4 Comments

This is a great answer. The documentation for Kernel#system is not sufficiently clear on this functionality. Very nice.
For ruby 1.8, look at @rtomayko's POSIX::Spawn, linked in another comment.
I am getting TypeError: no implicit conversion of Hash into String ...?
@Avdi do you know if there is a way to append a value at the end of the environment variable instead of replacing it? Something like: system({"INCLUDE" => "C:\Qt;%INCLUDE%", "echo %INCLUDE%"})
7

Ruby 1.9 includes Process::spawn which allows an environ hash to be provided.

Process::spawn is also the foundation for system, exec, popen, etc.
You can pass an environment to each.

Under Ruby 1.8, you may want to consider the POSIX::Spawn library,
which provides the same interfaces

2 Comments

Good to know! But the invocation is kinda clunky: Process.wait Process.spawn({"MYVAR" => "42"}, "echo $MYVAR") for my simple needs. Turns out the system func also supports this optional hash argument!
system accepts all arguments that Process.spawn() accepts. See my answer for example.
4

Using your same approach, but wrapped up as a block method that temporarily modifies the environment (like the block form of Dir.chdir):

def with_environment(variables={})
  if block_given?
    old_values = variables.map{ |k,v| [k,ENV[k]] }
    begin
       variables.each{ |k,v| ENV[k] = v }
       result = yield
    ensure
      old_values.each{ |k,v| ENV[k] = v }
    end
    result
  else
    variables.each{ |k,v| ENV[k] = v }
  end
end

with_environment 'RBENV_VERSION'=>'system' do
  `ruby extconf.rb`
end

3 Comments

I use such approach often in tests, but here it's an overkill.
@AnonymousDownvoter I encourage you to downvote answers that are wrong, and upvote answers that are better than others. Downvoting one (correct) answer presumably because there are other answers that are better (easier, shorter) is not in the spirit of Stack Overflow, IMHO.
+1 first, for getting an unfair downvote. 2nd, because this is my favorite answer. I was more excited until I realized you had defined :with_environment. It's sad, because that's the method that should exist in Ruby itself.
3

Actually that worked for me.

shai@comp ~ » irb                                                                                                                                     
1.9.3p0 :001 > system %{SHAIGUITAR=exists ruby -e 'puts ENV["SHAIGUITAR"]'}
exists
 => true 

But if it doesn't, maybe you can try prepending "env" to whatever variable you need. E.g.

system(%{env SHAIGUITAR=exists ruby bla.rb})

2 Comments

It works for me too. I'm an idiot, I tried it and discarded it after I didn't get the desired effect, but it was because of my particular use-case and not because this isn't supported. Thanks!
The only thing that doesn't work with this – and this is very weird – is the "echo" example. That's why I'm marking the other answer as correct – it covers more cases.
2

This may work?

system <<-CMD
export VARNAME=123
other_command
CMD

1 Comment

That works. One line: system 'export VARNAME=123 && other_command'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.