Take the 2-minute tour ×

If I call a command using system() in ruby, how do I get its output?


share|improve this question
add comment

14 Answers

up vote 175 down vote accepted

I'd like to expand & clarify chaos's answer a bit.

If you surround your command with backticks, then you don't need to (explicitly) call system() at all. The backticks execute the command and return the output as a string. You can then assign the value to a variable like so:

output = `ls`
p output
share|improve this answer
what if I need to give a variable as part of my command? That is, what would something like system("ls " + filename) translate into when backticks are to be used? –  Vijay Dev Dec 27 '09 at 17:08
You can do expression evaluation just as you would with regular strings: ls #{filename}. –  Craig Walker Dec 27 '09 at 17:38
Does this capture all output? –  knowncitizen Jan 21 '11 at 17:28
This answer isn't advisable: it introduces the new problem of unsanitized user input. –  Dogweather Apr 2 '12 at 10:46
if you want to capure stderr just put 2>&1 at the end of your command. e.g output = command 2>&1 –  micred May 16 '12 at 9:56
show 7 more comments

Just for the record, if you want both (output and operation result) you can do:

output=`ls no_existing_file` ;  result=$?.success?
share|improve this answer
This is exactly what I was looking for. Thank you. –  jdl Dec 1 '11 at 15:18
does this capture stderr? –  dfrankow May 11 '12 at 16:18
That only captures stdout, and stderr goes to the console. To get stderr, use: output=`ls no_existing_file 2>&1`; result=$?.success? –  peterept Jul 9 '12 at 1:44
This answer is unsafe and shouldn't be used -- if the command is anything but a constant, then the backtick syntax is likely to cause a bug, possibly a security vulnerability. (And even if it is a constant, it will probably cause someone to use it for a non-constant later and cause a bug.) See Simon Hürlimann's answer for a correct solution. –  Greg Price Jan 3 '13 at 3:15
add comment

Be aware that all the solutions where you pass a string containing user provided values to system, %x[] etc. are unsafe! Unsafe actually means: the user may trigger code to run in the context and with all permissions of the program.

As far as I can say only system and Open3.popen3 do provide a secure/escaping variant in Ruby 1.8. In Ruby 1.9 IO::popen also accepts an array.

Simply pass every option and argument as an array to one of these calls.

If you need not just the exit status but also the result you probably want to use Open3.popen3:

require 'open3'
stdin, stdout, stderr, wait_thr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username'])
exit_code = wait_thr.value

Note that the block form will auto-close stdin, stdout and stderr- otherwise they'd have to be closed explicitly.

More information here: Forming sanitary shell commands or system calls in Ruby

share|improve this answer
This is the only answer that actually answers the question and solves the problem without introducing new ones (unsanitized input). –  Dogweather Apr 2 '12 at 10:42
Thanks! This is the sort of answer I was hoping for. One correction: the gets calls should pass the argument nil, as otherwise we just get the first line of the output. So e.g. stdout.gets(nil). –  Greg Price Jan 4 '13 at 7:10
But where's the exit code? –  ConstableJoe Oct 14 '13 at 15:24
@ConstableJoe see stackoverflow.com/questions/15023944/… for more information. I've updated the example code to show how to get it. –  Simon Hürlimann Nov 1 '13 at 12:41
stdin, stdout and stderr should be closed explicitly in non-block form. –  Yarin Jan 12 at 5:22
show 2 more comments

You can use system() or %x[] depending what kind of result you need.

system() returning true if the command was found and ran successfully, false otherwise.

>> s = system 'uptime'
10:56  up 3 days, 23:10, 2 users, load averages: 0.17 0.17 0.14
=> true
>> s.class
=> TrueClass
>> $?.class
=> Process::Status

%x[..] on the other hand saves the results of the command as a string:

>> result = %x[uptime]
=> "13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> p result 
>> result.class
=> String

Th blog post by Jay Fields explains in detail the differences between using system, exec and %x[..] .

share|improve this answer
Thanks for the tip of using %x[]. It just solved a problem I had where I used back ticks in a ruby script in Mac OS X. When running the same script on a Windows machine with Cygwin, it failed because of the back ticks, but worked with %x[]. –  Henrik Warne Nov 2 '12 at 17:13
add comment

You use backticks:

share|improve this answer
Backticks do not produce output at the terminal. –  David Mar 29 '11 at 22:14
It doesn't produce stderr but it gives stdout. –  Nickolay Kondratenko Oct 16 '13 at 5:57
add comment

Another way is:

f = open("|ls")
foo = f.read()

Note that's the "pipe" character before "ls" in open. This can also be used to feed data into the programs standard input as well as reading its standard output.

share|improve this answer
add comment

If you need to escape the arguments, in Ruby 1.9 IO.popen also accepts an array:

p IO.popen(["echo", "it's escaped"]).read

In earlier versions you can use Open3.popen3:

require "open3"

Open3.popen3("echo", "it's escaped") { |i, o| p o.read }

If you also need to pass stdin, this should work in both 1.9 and 1.8:

out = IO.popen("xxd -p", "r+") { |io|
    io.print "xyz"
p out # "78797a"
share|improve this answer
Thanks! This is perfect. –  Greg Price Jan 4 '13 at 23:50
add comment

As a direct system(...) replacement you may use Open3.popen3(...)

Further discussion: http://tech.natemurray.com/2007/03/ruby-shell-commands.html

share|improve this answer
add comment

I found that the following is useful if you need the return value:

result = %x[ls]
puts result

I specifically wanted to list the pids of all the Java processes on my machine, and used this:

ids = %x[ps ax | grep java | awk '{ print $1 }' | xargs]
share|improve this answer
Which is it? %w or %x? Or do they both work? –  Platinum Azure Mar 2 '10 at 2:15
%x. I've updated the mistake above. –  Geoff Wilson Mar 16 '10 at 5:44
add comment

While using backticks or popen is often what you really want, it doesn't actually answer the question asked. There may be valid reasons for capturing system output (maybe for automated testing). A little Googling turned up an answer I thought I would post here for the benefit of others.

Since I needed this for testing my example uses a block setup to capture the standard output since the actual system call is buried in the code being tested:

require 'tempfile'

def capture_stdout
  stdout = $stdout.dup
  Tempfile.open 'stdout-redirect' do |temp|
    $stdout.reopen temp.path, 'w+'
    yield if block_given?
    $stdout.reopen stdout

So this gives us a method that will capture any output in the given block using a tempfile to store the actual data. Example usage:

captured_content = capture_stdout do
  system 'echo foo'
puts captured_content

Of course you can replace the system call with anything that might internally call system. You could also use the same method for capturing stderr if you wanted.

share|improve this answer
add comment

The straightforward way to do this correctly and securely is to use Open3.capture2(), Open3.capture2e(), or Open3.capture3().

Using ruby's backticks and its %x alias are NOT secure. It is DANGEROUS. When using it, escape untrusted data the same as you would in a shell:

untrusted = "foo; echo 'rm -rf *'"
out = `echo #{untrusted}`                              # BAD
out = `echo "#{untrusted}"`                            # good

The system function, in contrast, escapes arguments properly if used correctly:

ret = system "echo #{untrusted}"                       # BAD
ret = system 'echo', untrusted                         # good

Trouble is, it returns the exit code instead of the output, and capturing the latter is convoluted and messy.

The best answer in this thread so far mentions Open3, but not the functions that are best suited for the task. Open3.capture2, capture2e and capture3 work like system, but returns two or three arguments:

out, err, st = Open3.capture3("echo #{untrusted}")     # BAD
out, err, st = Open3.capture3('echo', untrusted)       # good
out_err, st  = Open3.capture2e('echo', untrusted)      # good
out, st      = Open3.capture2('echo', untrusted)       # good
p st.exitstatus

Another mentions IO.popen(). The syntax can be clumsy in the sense that it wants an array as input, but it works too:

out = IO.popen(['echo', untrusted]).read               # good

For convenience, you can wrap Open3.capture3() in a function, e.g.:

# Returns stdout on success, false on failure, nil on error
def syscall(*cmd)
    stdout, stderr, status = Open3.capture3(*cmd)
    status.success? && stdout.slice!(0..-(1 + $/.size)) # strip trailing eol


p system('foo')
p syscall('foo')
p system('which', 'foo')
p syscall('which', 'foo')
p system('which', 'which')
p syscall('which', 'which')

Yields the following:

/usr/bin/which         <— stdout from system('which', 'which')
true                   <- p system('which', 'which')
"/usr/bin/which"       <- p syscall('which', 'which')
share|improve this answer
This is the correct answer. It is also the most informative. The only thing missing is a warning about closing the std*s. See this other comment: require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read } Note that the block form will auto-close stdin, stdout and stderr- otherwise they'd have to be closed explicitly. –  Peter H. Boling Feb 4 at 17:02
@PeterH.Boling: Best I'm aware, the capture2, capture2e and capture3 also close them std*s automatically. (At the very least, I never ran into the problem on my end.) –  Denis Feb 4 at 17:14
without using the block form there is no way for a codebase to know when something should be closed, so I highly doubt they are being closed. You probably never ran into a problem because not closing them won't cause problems in a short lived process, and if you restart a long-running process often enough, otto won't show up there either unless you are opening std*s in a loop. Linux has a high file descriptor limit, which you can hit, but until you hit it you won't see the "bug". –  Peter H. Boling Mar 9 at 20:20
@PeterH.Boling: No no, see the source code. The functions are just wrappers around Open3#popen2, popen2e and popen3 with a predefined block: ruby-doc.org/stdlib-2.1.1/libdoc/open3/rdoc/… –  Denis Mar 10 at 8:28
add comment

If you want the output redirected to a file using Kernel#system, you can do modify descriptors like this:

redirect stdout and stderr to a file(/tmp/log) in append mode:

system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])

For a long running command, this will store the output in real time. You can also, store the output using a IO.pipe and redirect it from Kernel#system.

share|improve this answer
add comment

You may want to have a look at this thread in comp.lang.ruby

share|improve this answer
This is a very hand thread, thanks. The class for running commands and getting feedback is great in the sample code. –  ylluminate Nov 1 '11 at 15:16
add comment

As Simon Hürlimann already explained, Open3 is safer than backticks etc.

require 'open3'


share|improve this answer
Thanks for this. –  Peter H. Boling Feb 4 at 17:03
add comment

Your Answer


