Question
How can I run shell commands from inside a Ruby program? Also, how can I capture the output of those commands and use it inside Ruby?
Short Answer
By the end of this page, you will understand the main ways Ruby can execute shell commands, how to capture standard output, how to detect success or failure, and when to use safer options such as system, backticks, %x, and Open3.
Concept
Ruby can launch external programs such as shell commands, scripts, and command-line tools. This is useful when your Ruby code needs to interact with the operating system or reuse existing tools.
Common examples include:
- listing files with
ls - running
gitcommands - calling image-processing tools
- executing deployment scripts
- reading output from utilities like
whoamiordate
The important idea is that Ruby and the shell are separate environments:
- Ruby runs your application logic
- The shell runs system commands
- Ruby can start a command, wait for it, and optionally capture its output
Ruby provides several ways to do this, and each one has a different purpose:
systemruns a command and returnstrueorfalsedepending on success- backticks
`command`run a command and return its standard output as a string %x(command)is another form of backticksOpen3gives more control and can capture standard output, standard error, and exit status separately
This matters in real programming because external commands often produce useful data, but they can also fail, hang, or behave differently across operating systems. Choosing the right Ruby method helps you write safer and clearer code.
Mental Model
Think of Ruby as a manager and shell commands as workers.
- If Ruby just wants a worker to do a task and report whether it succeeded, use
system. - If Ruby wants the worker to bring back a note with the result, use backticks or
%x. - If Ruby wants a full report with output, errors, and status, use
Open3.
Another way to picture it:
system= press a button and check whether the machine worked- backticks = press a button and collect the printed receipt
Open3= collect the receipt, the error log, and the final status code
Syntax and Examples
Basic ways to run shell commands in Ruby
1. system
Use system when you want to run a command and mainly care whether it succeeds.
success = system("ls")
puts success
- The command runs in the shell.
- Output is printed directly to the terminal.
- The return value is usually
truefor success andfalsefor failure.
2. Backticks
Use backticks when you want the command output as a Ruby string.
output = `whoami`
puts output
Example output:
alice
The value stored in output includes the command's standard output.
3. %x()
This is another syntax for backticks.
output = %x(date)
puts output
This is useful if backticks are harder to read in a longer string.
4. Open3.capture3
Use this when you want output, error output, and exit status separately.
require "open3"
stdout, stderr, status = Open3.capture3("ls missing_file")
puts "STDOUT: #{stdout}"
puts "STDERR: #{stderr}"
puts "SUCCESS?: #{status.success?}"
puts "EXIT CODE: #{status.exitstatus}"
This is often the best choice when building robust scripts.
Example: capture a command result and use it in Ruby
current_user = `whoami`.strip
puts "Logged in as: #{current_user}"
Why strip?
Many shell commands return output ending with a newline. strip removes that extra whitespace.
Safer argument passing
Instead of building a shell string manually, Ruby can pass arguments directly.
system("ls", "-l", "/tmp")
This is usually safer than:
system("ls -l /tmp")
Passing separate arguments avoids many quoting and escaping problems.
Step by Step Execution
Example
output = `echo Hello`
message = output.strip
puts message
What happens step by step
1. Ruby sees the backticks
output = `echo Hello`
Ruby runs the shell command echo Hello.
2. The shell executes the command
The command prints this text to standard output:
Hello
Usually there is a newline at the end.
3. Ruby captures the output
The captured string becomes the value of output:
"Hello\n"
4. strip removes extra whitespace
message = output.strip
Now message is:
"Hello"
5. Ruby prints the cleaned result
puts message
The final output shown in the terminal is:
Hello
Another trace with success checking
success = system("ruby", "-v")
puts success
Step by step:
- Ruby starts the
ruby -vcommand. - The command prints the Ruby version directly to the terminal.
- If the command exits successfully,
successbecomestrue. puts successprintstrue.
This example shows the key difference:
systemshows output directly- backticks return output to Ruby
Real World Use Cases
Practical uses
Running Git commands
A Ruby deployment script might check the current branch:
branch = `git branch --show-current`.strip
Calling system tools
A script may need the hostname of the machine:
hostname = `hostname`.strip
Processing files with external tools
Ruby might call tools like ffmpeg, convert, or tar.
system("tar", "-czf", "backup.tar.gz", "project_folder")
Automation scripts
A Ruby script can gather system information and generate a report.
disk_usage = `df -h`.strip
puts disk_usage
CI/CD and deployment
Build scripts often run commands such as:
bundle installgit pullrake db:migrate
Admin and maintenance tasks
Ruby can be used for:
- restarting services
- checking logs
- cleaning temporary files
- running scheduled jobs
Real Codebase Usage
How developers use this in real projects
Guard clauses for failed commands
Developers often stop early if a required command fails.
unless system("git", "fetch")
abort("Failed to fetch latest changes")
end
This keeps scripts simple and clear.
Capturing output for validation
A program might check a command result before continuing.
ruby_version = `ruby -v`.strip
abort("Ruby is not installed") if ruby_version.empty?
Using Open3 for error handling
When stderr matters, Open3 is common.
require "open3"
stdout, stderr, status = Open3.capture3("git status --short")
abort(stderr) unless status.success?
puts stdout
Avoiding shell interpolation with user input
In production code, developers avoid unsafe string building.
filename = "report.txt"
system("cat", filename)
This is better than interpolating directly into one shell string.
Logging command execution
Real codebases often log commands before running them.
command = ["ls", "-l"]
puts "Running: #{command.join(' ')}"
system(*command)
Wrapping commands in helper methods
Teams often create small helper functions.
require "open3"
def run_command(*args)
stdout, stderr, status = Open3.capture3(*args)
{
stdout: stdout,
stderr: stderr,
success: status.success?,
exit_code: status.exitstatus
}
end
result = run_command("ruby", "-v")
puts result[:stdout] if result[:success]
Common Mistakes
1. Expecting system to return command output
Broken example:
output = system("whoami")
puts output
Why this is wrong:
systemreturnstrueorfalse- it does not return the command output
Correct version:
output = `whoami`
puts output
2. Forgetting to remove the trailing newline
name = `whoami`
puts "User: #{name}!"
This may print awkward formatting because name often contains \n.
Better:
name = `whoami`.strip
puts "User: #{name}!"
3. Ignoring command failure
output = `some_missing_command`
puts output
A command can fail silently from your program's point of view unless you check status.
Better approach:
output = `some_missing_command`
status = $?
puts status.success?
4. Building unsafe command strings
Broken example:
filename = params[:filename]
system("cat #{filename}")
If filename comes from a user, this can be dangerous.
Safer:
filename = params[:filename]
system("cat", filename)
5. Forgetting stderr exists
Backticks capture standard output, not standard error in a structured way.
If you need both stdout and stderr separately, prefer Open3.capture3.
require "open3"
stdout, stderr, status = Open3.capture3("ls missing_file")
6. Assuming shell commands are portable
Commands like ls, grep, and df may not work the same way on every operating system.
Avoid this mistake by:
- checking the target environment
- using Ruby's standard library when possible
- documenting system requirements
Comparisons
Common Ruby options for running shell commands
| Method | Returns | Shows output in terminal | Captures stdout | Captures stderr separately | Best for |
|---|---|---|---|---|---|
system("cmd") | true/false | Yes | No | No | Run a command and check success |
`cmd` | String | No, captured instead | Yes | No | Get command output as a string |
%x(cmd) | String | No, captured instead | Yes | No | Same as backticks, alternate syntax |
Open3.capture3("cmd") | stdout, stderr, status | No, captured instead | Yes | Yes | Robust scripts and error handling |
system vs backticks
| Feature | system | Backticks |
|---|---|---|
| Main purpose | Execute a command | Execute and capture output |
| Return value | Boolean-like success result | Output string |
| Output destination | Terminal | Ruby variable |
| Good for | Tasks, installers, scripts | Reading command results |
Shell string vs argument list
| Style | Example | Notes |
|---|---|---|
| Shell string | system("ls -l /tmp") | Simpler to type, but quoting can be tricky |
| Argument list | system("ls", "-l", "/tmp") | Safer and clearer for dynamic values |
When to use which
- Use
systemif you only need to know whether the command worked. - Use backticks or
%xif you need the output as a string. - Use
Open3if you need proper error handling and both output streams.
Cheat Sheet
Quick reference
Run a command and check success
success = system("ls")
Run a command and capture output
output = `whoami`
output = output.strip
Alternative to backticks
output = %x(date)
Capture stdout, stderr, and status
require "open3"
stdout, stderr, status = Open3.capture3("ls missing_file")
Check the last exit status
output = `ls`
puts $?.success?
puts $?.exitstatus
Safer argument passing
system("ls", "-l", "/tmp")
Rules to remember
systemreturns success, not command output- backticks return stdout as a string
- command output often ends with
\n, so usestrip - use
Open3when stderr and exit status matter - prefer argument lists over interpolated shell strings for safety
Edge cases
- some commands behave differently across platforms
- missing commands may fail even if Ruby code itself is valid
- external commands can be slow, so avoid calling them repeatedly without need
FAQ
How do I capture shell command output in Ruby?
Use backticks or %x() if you want the command's standard output as a string.
What is the difference between system and backticks in Ruby?
system runs a command and returns whether it succeeded. Backticks run a command and return its output.
How do I get both stdout and stderr from a command in Ruby?
Use Open3.capture3 from Ruby's standard library.
How can I check if a shell command succeeded in Ruby?
With system, check the returned value. With backticks or Open3, inspect the exit status using $? or the returned status object.
Should I use shell commands or pure Ruby methods?
If Ruby's standard library can do the job, that is often more portable and easier to test. Use shell commands when you need existing system tools.
Is it safe to build commands with string interpolation?
Not always. If the values come from users or external input, prefer passing arguments separately to avoid shell injection issues.
Why does captured command output contain a newline?
Many shell commands print a trailing newline. Use .strip or .chomp to remove it.
Mini Project
Description
Build a small Ruby command runner that executes a system command, captures its output, and reports whether it succeeded. This demonstrates the difference between output, errors, and exit status in a practical script.
Goal
Create a Ruby script that runs a command entered in code, prints stdout and stderr separately, and shows the exit code.
Requirements
- Use Ruby and the
open3standard library. - Run at least one external command from the script.
- Capture standard output, standard error, and exit status.
- Print a clear success or failure message.
- Show the numeric exit code.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
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.