Question
In Ruby, if I run a shell command using Kernel#system, how can I get the command's output?
For example:
system("ls")
I want to understand how to access what the command prints, rather than only running it.
Short Answer
By the end of this page, you will understand why system("ls") prints output to the terminal but does not return that output as a string. You will learn the difference between system, backticks, %x[], and Open3, and you will know which one to use when you need command output, exit status, or error output in Ruby.
Concept
Kernel#system is used to run an external command. Its main job is to execute the command and return whether it succeeded.
That means:
system(...)returnstrueif the command exits successfullysystem(...)returnsfalseif the command exits with a failure statussystem(...)returnsnilif the command could not be executed at all
A very important detail is that system does not return the command output. Instead, the command's standard output usually goes directly to the terminal.
If you need the output as a Ruby string, use one of these:
- backticks:
`ls` %x[ls]Open3.capture2,Open3.capture3, or related methods
Why this matters in real programming:
- Scripts often need to read the output of another program
- Build tools may need to parse command results
- Deployment scripts may need both output and exit status
- Error handling often requires access to as well as
Mental Model
Think of system like pressing a button on a machine and watching it work in front of you.
- You press the button
- The machine prints messages to the screen
- At the end, it tells you only whether it succeeded
It does not hand you a copy of everything it printed.
Backticks and Open3 are more like giving the machine a recorder:
- The command still runs
- But now the output is captured for your Ruby program to inspect
So:
system= run it and observe- backticks = run it and capture the printed result
Open3= run it and capture output with more control
Syntax and Examples
The most common options are:
1. system
success = system("ls")
p success
This prints the ls output to the terminal, and then success will usually be true if the command worked.
2. Backticks
output = `ls`
puts output
This captures the command's standard output and stores it in output.
3. %x[]
output = %x[ls]
puts output
This is another syntax for backticks. It behaves the same way.
4. Open3.capture2
require "open3"
stdout, status = Open3.capture2("ls")
puts stdout
puts status.success?
This captures standard output and also gives you the exit status.
5.
Step by Step Execution
Consider this example:
require "open3"
stdout, stderr, status = Open3.capture3("ruby -v")
puts "Output: #{stdout}"
puts "Errors: #{stderr}"
puts "Success?: #{status.success?}"
Step by step:
-
require "open3"- Loads Ruby's standard library for running external commands with more control.
-
Open3.capture3("ruby -v")- Runs the command
ruby -v - Captures anything written to standard output
- Captures anything written to standard error
- Returns the process exit status
- Runs the command
-
stdout, stderr, status = ...stdoutbecomes the normal command outputstderrbecomes the error outputstatusbecomes aProcess::Statusobject
Real World Use Cases
Capturing command output is common in many Ruby programs.
1. Checking Git information
branch = `git branch --show-current`.strip
puts "Current branch: #{branch}"
Useful in deployment scripts or developer tools.
2. Reading system information
hostname = `hostname`.strip
puts hostname
Useful in server automation.
3. Running build or test commands
output = `rspec`
puts output
Useful when a script needs to log or analyze test results.
4. Validating external tools
require "open3"
stdout, stderr, status = Open3.capture3("node -v")
if status.success?
puts "Node is installed: #{stdout.strip}"
else
puts "Node is not available: #{stderr}"
end
Useful in setup scripts.
5. Parsing command results
Real Codebase Usage
In real projects, developers usually choose the command API based on what they need.
Common patterns
Use system for simple success/failure
abort("Deploy failed") unless system("cap production deploy")
This is common in scripts where the command should stream directly to the terminal.
Use backticks for quick stdout capture
version = `git rev-parse --short HEAD`.strip
This is convenient for short scripts, but less flexible for error handling.
Use Open3 when output and errors both matter
require "open3"
stdout, stderr, status = Open3.capture3("convert input.png output.jpg")
raise stderr unless status.success?
This is common in production code because it gives better control.
Guard clause for command failure
require "open3"
stdout, stderr, status = Open3.capture3("my_command")
status.success?
puts stdout
Common Mistakes
1. Expecting system to return output
Broken example:
output = system("ls")
puts output
Why this is wrong:
outputwill betrue,false, ornil- it will not contain the file list
Use this instead:
output = `ls`
puts output
2. Forgetting to remove trailing newlines
branch = `git branch --show-current`
puts "Branch: #{branch}!"
This often produces awkward formatting because command output usually ends with a newline.
Better:
branch = `git branch --show-current`.strip
puts "Branch: #{branch}!"
3. Ignoring command failure
output = `some_missing_command`
puts output
Comparisons
| Approach | Returns | Captures stdout? | Captures stderr? | Best for |
|---|---|---|---|---|
system("cmd") | true, false, or nil | No | No | Running a command and checking success |
`cmd` | String | Yes | No | Quick output capture |
%x[cmd] | String | Yes | No | Same as backticks |
Cheat Sheet
# Run command, print directly to terminal, return success/failure
ok = system("ls")
# Capture stdout as a string
output = `ls`
output = %x[ls]
# Check exit status after backticks
output = `ls`
$?.success?
# Capture stdout and exit status
require "open3"
stdout, status = Open3.capture2("ls")
# Capture stdout, stderr, and exit status
require "open3"
stdout, stderr, status = Open3.capture3("ls /missing")
# Remove trailing newline from command output
text = `hostname`.strip
Rules to remember
systemdoes not return command output- backticks return stdout as a string
- use
.stripwhen you want clean output - use
Open3.capture3when stderr matters - check
status.success?or$?.success?when failure matters
Edge cases
- A command may print nothing and still succeed
- A command may fail and write the useful message to stderr only
FAQ
How do I get the output of a shell command in Ruby?
Use backticks like output = `ls` or use Open3.capture2 / Open3.capture3 for more control.
Why does system("ls") not return the file list?
Because system is designed to run the command and return success or failure, not the printed output.
What does system return in Ruby?
It returns true for success, false for command failure, and nil if the command could not be executed.
Should I use backticks or Open3 in Ruby?
Use backticks for simple scripts when you only need stdout. Use Open3 when you also need stderr or explicit exit-status handling.
How do I capture stderr in Ruby?
Use Open3.capture3, which returns stdout, stderr, and status separately.
How do I know if a backtick command succeeded?
Mini Project
Description
Build a small Ruby command runner that asks for a command, executes it, and shows the captured output, captured errors, and whether the command succeeded. This demonstrates the practical difference between simply running a command and actually reading its result inside Ruby.
Goal
Create a Ruby script that runs an external command and prints stdout, stderr, and exit status clearly.
Requirements
- Use Ruby's
Open3library - Run at least one external command and capture its output
- Print standard output and standard error separately
- Show whether the command succeeded
- Clean up output with
.stripwhere appropriate
Keep learning
Related questions
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.
Convert a Unix Timestamp to Ruby DateTime
Learn how to convert Unix timestamps to Ruby DateTime and Time objects, with examples, differences, pitfalls, and practical Ruby usage.