views:

9910

answers:

11

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?

+1  A: 

The Ruby Kernel object is one option. Check out these links:

http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html

http://www.ruby-doc.org/core/classes/Kernel.html

qrush
A: 

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)
Steve Willard
A: 

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.

Rufo Sanchez
+26  A: 

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
cynicalman
The only bad thing about this approach is moving your code to Windows. (You might be surprised when stuff you've written absolutely *has* to run on XP, but you forgot you used a bash command in there someplace that you can no longer use.) That being said, you can use the pure-Ruby `Find` module (and `Array#sort`) to do the same thing on any platform. The more excotic commands are harder to replace (especially if you're doing GUI programming in Windows, which *always* pops up a DOS window when you use `%x()`).
Benjamin Oakes
+30  A: 

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
Steve Willard
+6  A: 

Some things to think about when choosing between these mechanisms are:

  1. Do you just want stdout or do you need stderr as well? or even separated out?
  2. How big is your output? Do you want to hold the entire result in memory?
  3. Do you want to read some of your output while the subprocess is still running?
  4. Do you need result codes?
  5. 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.

Nick Brosnahan
+9  A: 

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.

Mihai A
That link is broken. Is http://tech.natemurray.com/2007/03/ruby-shell-commands.html the equivalent?
Andrew Grimm
Yes, I updated the post. Thank you.
Mihai A
+2  A: 

My favourite is Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
anshul
A: 

A good overview can be found here

http://pasadenarb.com/2007/03/ruby-shell-commands.html

Ben Brinckerhoff
Piku's answer also linked to that blog post.
Andrew Grimm
A: 

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.

Fred
+1  A: 

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.

j-g-faustus