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!
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}]
}
Ruby 1.9.3 (blocking call):
require 'open3'
Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
p o.read.chomp #=> "/"
}
Dir.pwd #=> "/home/abe"
also, taking the shell route
%x[cd #{dir} && #{cmd}]
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.
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.
I had this same problem and solved it by putting both commands in back ticks and separating with '&&':
`cd \desired\directory && command`
Related
#!/home/user/.rvm/rubies/ruby-2.0.0-p353/bin/ruby
case ARGV[0]
when "apache"
exec('cd /etc/apach2')
exec('sudo nano httpd.conf')
#...
end
I am trying to make a quick command line tool that will change directories for me with one word.. so from the command line (in ubuntu 12). It tells me it cant cd.. But I try the command myself and it will work just fine.
Ruby's Dir class is your friend for this, check-out the chdir method:
Dir.chdir('/path/to/change/to')
will change Ruby's concept of the current working directory for the time the code is running. Any sub-shells would consider that their starting directory.
You can also pass chdir a block, and all code in that block will assume the new directory, which will then revert to the old one when the block exits:
Dir.chdir('/path/to/change/to') do
# do some stuff
end
OK, so I did this and it works (I'm on OS X but should be the same):
ARGV[0]
when "testme"
system('cd ripple')
system('ls -al')
#...
end
calling system('cd ... does not change move you to that directory in the current shell you are executing your .rb file in. So it would make more sense to do:
system('sudo nano /etc/....
all on one line
I tested it with back ticks and it didn't work at all for me.
I tested with exec() and got the expected result, it runs one line and that's it. So exec() could work if you only have one command to run or you chain them all together with &&
exec('ls /etc && sudo nano /etc/....
I would read this: http://rubyquicktips.com/post/5862861056/execute-shell-commands
Is there a way to pass ruby file, foo.rb to rails console. Expected results would be after console starts rails environment to run file.
Or any other way which would allow me to execute file in rails environment, triggered from command prompt.
Actually, the simplest way is to run it with load inside the rails console
load './path/to/foo.rb'
You can use
bundle exec rails runner "eval(File.read 'your_script.rb')"
UPDATE:
What we also have been using a lot lately is to load the rails environment from within the script itself. Consider doit.rb:
#!/usr/bin/env ruby
require "/path/to/rails_app/config/environment"
# ... do your stuff
This also works if the script or the current working directory are not within the rails app's directory.
In the meantime, this solution has been supported.
rails r PATH_TO_RUBY_FILE
Much simpler now.
Consider creating a rake task.
For code that I need to create records or support migrations, for example, I often create a rake task like that from this answer. For example:
In lib/tasks/example.rake:
namespace :example do
desc "Sample description you'd see if you ran: 'rake --tasks' in the terminal"
task create_user: :environment do
User.create! first_name: "Foo", last_name: "Bar"
end
end
And then in the terminal run:
rake example:create_user
script/console --irb=pry < test.rb > test.log
simple, dirty, and block the process at the end, but it does the job exactly like I wanted.
Of these approaches mentioned earlier, none seemed clean and ideal like you would expect a standalone script to run (not get eval-ed or piped via < redirection), but finally this works perfect for me:
(for Rails 3)
Insert at the top of your script:
#!/usr/bin/env ruby
APP_PATH = File.expand_path(appdir = '/srv/staging/strat/fundmgr/config/application', __FILE__)
require File.expand_path(appdir + '/../boot', __FILE__)
require APP_PATH
# set Rails.env here if desired
Rails.application.require_environment!
# your code here...
Of course, set your own Rails app path in the APP_PATH line.
That way, I can avoid having to enter any interactive irb or rails c and can test my script.rb from the shell prompt, before eg. scheduling it in crontab.
It smoothly supports command-line parameters, too, and minimizes the levels of wrappers before getting to your code.
CREDIT (also shows a Rails 2 example)
http://zerowidth.com/2011/03/18/standalone-script-runner-bin-scripts-in-rails.html
Here's the hack I'm using:
rr() {
rails_root="$(bundle exec rails runner "puts Rails.root")"
rp="$(relpath "$1" "$rails_root")"
bundle exec rails runner "eval(File.read '$rp')"
}
relpath() {python -c "import os.path; print os.path.relpath('$1','${2:-$PWD}')";}
Example:
cd ~/rails_project/app/helpers
rr my_script.rb
Based on #moritz's answer here. I changed it, since the working directory for File.read is the Rails project root.
I know this is some serious heresy, using python to help a ruby script. But I couldn't find a relpath method built into ruby.
Credit: relpath() was taken from #MestreLion, Convert absolute path into relative path given a current directory using Bash
I have to run a whole bunch of ruby scripts to generate some results. In which order does not matter. I just don't want to do Ruby file1.rb, Ruby file2.rb, Ruby file3.rb...one by one.
Could I write a script that group all files together and issue command only once to run them all?
I would do it ruby-style and use rake gem.
I would create file named "rakefile.rb" and this would be its content:
task :default do
FileList['file*.rb'].each { |file| ruby file }
end
Then I would call rake in my favourite shell and I would enjoy it.
Bonus: It's multiplatform.
Assuming you are using bash and all the ruby files you want to run are in the current directory you could do:
for file in `ls ./*.rb`; do
ruby $file
done
Have runall.rb contain:
(1..3).each do |i|
`ruby file#{i}.rb`
end
and call ruby runall.rb.
You could make a sh script called startruby.sh that looks like this (this example doesn't work):
ruby ruby1.rb;
ruby ruby2.rb;
etc.
And then run
sh startruby.sh
And it will lauch all the ruby script after each other.
Offcourse you can also make it more advanced with a for loop and such, but this is the easiest/quickest way.
Depends on what you want, but if you want all the files loaded together, maybe something like ...
ruby -I. -e "ARGV.each {|f| load f}" file*.rb
I want to capture output from shell commands so I am using
response = `#{command}`
which is fine if you want to run only one command and not a continuous interaction. For instance if I do
response = `cd tmp`
# response = '', which is correct
response = `ls`
I would like it to return ls for within tmp, since in the previous command I had changed directory to temp. Is there a way to run a continuous shell on its own Thread or a gem or something to that effect?
The ` starts a sub-shell, so it does not affect your current Ruby shell. However you can use Ruby's Dir.chdir or FileUtils.cd to change the working directory of your Ruby shell.
Btw, maybe you like fresh, which is a hybrid between a system and a Ruby shell. You can normally use cd/ls there, while being in a Ruby shell.
I want to write a script, to be packaged into a gem, which will modify its parameters and then exec a new ruby process with the modified params. In other words, something similar to a shell script which modifies its params and then does an exec $SHELL $*. In order to do this, I need a robust way of discovering the path of the ruby executable which is executing the current script. I also need to get the full parameters passed to the current process - both the Ruby parameters and the script arguments.
The Rake source code does it like this:
RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).
sub(/.*\s.*/m, '"\&"')
If you want to check on linux: read files:
/proc/PID/exe
/proc/PID/cmdline
Other useful info can be found in /proc/PID dir
For the script parameters, of course, use ARGV.
File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])