How do I call console/bash commands from inside of a Ruby Program? Also, how do I get output from these commands back into my program?
The Ruby Kernel object is one option. Check out these links:
http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html
Definitely not a ruby expert, but I'll give it a shot.
$ irb
system "echo Hi"
Hi
=> true
You should also be able to do things like...
cmd = 'ls'
system(cmd)
You can also use the backtick operators (`), similar to Perl:
directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory
Handy if you need something simple.
Which method you want to use depends on exactly what you're trying to accomplish; check the docs for more details about the different methods.
The way I like to do this is using the %x operator, which makes it easy (and readable!) to use quotes in a command, like so:
directorylist = %x[find . -name '*test.rb' | sort]
Which, in this case, will populate file list with all test files under the current directory, which you can process as expected:
directorylist.each do |filename|
filename.chomp!
# work with file
end
Edit: If you want to improve this script, feel free to update it it using the following link.
From a friend of mine. http://gist.github.com/4069
# Ways to execute a shell script
cmd = "echo 'hi'" # Sample string that can be used
# 1. Kernel#` - commonly called backticks - `cmd`
# This is like many other languages, including bash, PHP, and Perl
# Returns the result of the shell command
# Docs: http://ruby-doc.org/core/classes/Kernel.html#M001111
value = `echo 'hi'`
value = `#{cmd}`
# 2. Built-in syntax, %x( cmd )
# Following the ``x'' character is a delimiter, which can be any character.
# If the delimiter is one of the characters ``('', ``['', ``{'', or ``<'',
# the literal consists of the characters up to the matching closing delimiter,
# taking account of nested delimiter pairs. For all other delimiters, the
# literal comprises the characters up to the next occurrence of the
# delimiter character. String interpolation #{ ... } is allowed.
# Returns the result of the shell command, just like the backticks
# Docs: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html
value = %x( echo 'hi' )
value = %x[ #{cmd} ]
# 3. Kernel#system
# Executes the given command in a subshell,
# Return: true if the command was found and ran successfully, false otherwise
# Docs: http://ruby-doc.org/core/classes/Kernel.html#M002992
wasGood = system( "echo 'hi'" )
wasGood = system( cmd )
# 4. Kernel#exec
# Replaces the current process by running the given external command.
# Return: none, the current process is replaced and never continues
# Docs: http://ruby-doc.org/core/classes/Kernel.html#M002992
exec( "echo 'hi'" )
exec( cmd ) # Note: this will never be reached beacuse of the line above
# Extra Advice
# $? which is the same as $CHILD_STATUS
# Accesses the status of the last system executed command if
# you use the backticks, system() or %{}.
# You can then access the ``exitstatus'' and ``pid'' properties
$?.exitstatus
# More Reading
# http://www.elctech.com/blog/i-m-in-ur-commandline-executin-ma-commands
# http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html
Some things to think about when choosing between these mechanisms are:
- Do you just want stdout or do you need stderr as well? or even separated out?
- How big is your output? Do you want to hold the entire result in memory?
- Do you want to read some of your output while the subprocess is still running?
- Do you need result codes?
- Do you need a ruby object that represents the process and lets you kill it on demand?
You may need anything from simple backticks (``), system(), and IO.popen to full-blown Kernel.fork/Kernel.exec with IO.pipe and IO.select.
You may also want to throw timeouts into the mix if a subprocess takes too long to execute.
Unfortunately, it very much depends.
Here's the best article in my opinion about running shell scripts in ruby: 6 Ways to Run Shell Commands in Ruby
If you only need to get the output use backticks.
I needed more advanced stuff like STDOUT and STDERR so I used Open4 gem. You have all the methods explained there.
What about synchronization issues? Is there a way to get the Bash commands to execute fully before the rest of the ruby code gets executed, or test for completion? I saw in ri that system runs in a sub shell, and trying a: system("clear") at the top of my script cleared the screen after the rest of the code was done.
Great info here BTW, I'm just getting started with Ruby.
One more option:
When you
- need stderr as well as stdout
- can't/won't use Open3/Open4 (they throw exceptions in NetBeans on my Mac, no idea why)
you can use shell redirection:
puts %x[cat bogus.txt].inspect
=> ""
puts %x[cat bogus.txt 2>&1].inspect
=> "cat: bogus.txt: No such file or directory\n"
The 2>&1
syntax works across Linux, Mac and Windows since the early days of MS-DOS.