65

I know how to run a shell command in Ruby like:

%x[#{cmd}]

But, how do I specify a directory to run this command?

Is there a similar way of shelling out, similar to subprocess.Popen in Python:

subprocess.Popen(r'c:\mytool\tool.exe', cwd=r'd:\test\local')

Thanks!

6 Answers 6

155

You can use the block-version of Dir.chdir. Inside the block you are in the requested directory, after the Block you are still in the previous directory:

Dir.chdir('mydir'){
  %x[#{cmd}]
}
Sign up to request clarification or add additional context in comments.

3 Comments

The things like this that Ruby does with blocks never cease to amaze me. Ruby constantly makes my other languages feel clunky and overcomplicated.
Dir.chdir is ok if you have a single thread. For multiple threads look at the other answers here.
This is great for single-threaded scripts. It is not safe for launching multiple processes in parallel.
16

Ruby 1.9.3 (blocking call):

require 'open3'
Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
  p o.read.chomp #=> "/"
}

Dir.pwd #=> "/home/abe"

Comments

5

The closest I see to backtricks with safe changing dir is capture2:

require 'open3'
output, status = Open3.capture2('pwd', :chdir=>"/tmp")

You can see other useful Open3 methods in ruby docs. One drawback is that jruby support for open3 is rather broken.

1 Comment

Using the :chdir option of any Process.spawn-based invokation (system, popen3,...) seems to be thread-safe for launching parallel processes, too.
4

also, taking the shell route

%x[cd #{dir} && #{cmd}]

Comments

1

Maybe it's not the best solution, but try to use Dir.pwd to get the current directory and save it somewhere. After that use Dir.chdir( destination ), where destination is a directory where you want to run your command from. After running the command use Dir.chdir again, using previously saved directory to restore it.

3 Comments

You can also use the block-version of Dir.chdir. Inside the block you are in the requested directory, after the Block you are still in the previous directory.
@knut You should make that an answer - I like it! I was going to suggest something crazy like Dir.chdir(Dir.pwd.tap {Dir.chdir('d:\test\local'); #otherstuff}) as I wasn't aware chdir could take a block
@AbeVoelker You are right, here it is
1

I had this same problem and solved it by putting both commands in back ticks and separating with '&&':

`cd \desired\directory && command`

Comments

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.