Question
Ruby exec vs system vs backticks (%x): Differences, Return Values, and When to Use Each
Question
In Ruby, what is the difference between exec, system, and %x() (or backticks) when running shell commands?
I understand that all three can execute terminal commands from Ruby, but I want to know why Ruby provides multiple ways to do this and when each one should be used.
Short Answer
By the end of this page, you will understand how Ruby runs external commands using exec, system, and backticks (%x()), and why they behave differently. You will learn which one replaces the current process, which one returns a success value, which one captures command output, and how to choose the right tool for real programs.
Concept
Ruby gives you multiple ways to run external commands because programs often need different kinds of behavior.
At first glance, exec, system, and backticks all seem similar because they all run a shell command. But they answer different needs:
exec: replace the current Ruby process with another programsystem: run a command and wait for it to finish, returning whether it succeeded- backticks /
%x(): run a command and capture its standard output as a string
These differences matter because when you run another program, you usually care about one or more of these questions:
- Should Ruby continue running afterward?
- Do I need the command's output?
- Do I only care whether it succeeded?
- Do I want to fully hand control over to another executable?
exec
exec does not start a child process and then return to Ruby in the usual way. Instead, it replaces the current Ruby process with the target command.
That means:
- Ruby code after
execwill not run ifexecsucceeds - The operating system process becomes the new program
- This is useful when Ruby is only acting as a launcher
system
system runs a command, waits for it to finish, and returns:
Mental Model
Think of Ruby as a person sending work to another worker.
execis like Ruby taking off its badge and letting the other worker take its place completely. Ruby is gone.systemis like Ruby asking another worker to do a job, waiting for the result, and hearing only whether it succeeded or failed.- backticks /
%x()are like Ruby asking another worker to do a job and bring back a written report of the output.
So the main question is:
Do you want to replace yourself, check success, or capture output?
That choice determines which tool to use.
Syntax and Examples
Core syntax
exec("ls")
system("ls")
output = `ls`
output = %x(ls)
Example: system
success = system("mkdir test_folder")
puts success
If the command succeeds, success will usually be true.
Example: backticks
files = `ls`
puts files
Here, the command output is stored in files as a string.
Example: exec
puts "Before exec"
exec("ls")
puts "After exec"
If exec succeeds:
Before execis printedlsruns
Step by Step Execution
Consider this example:
puts "Start"
result = system("ruby -e 'puts 1 + 1'")
puts "Command success: #{result}"
puts "Exit status: #{$?.exitstatus}"
puts "End"
Step by step
-
Ruby prints:
Start -
Ruby runs this external command:
ruby -e 'puts 1 + 1' -
That external Ruby process prints:
2 -
The command finishes successfully.
-
system(...)returnstrue, soresultbecomestrue. -
$?.exitstatusis usually0, which means success. -
Ruby prints:
Real World Use Cases
When to use exec
Use exec when your Ruby program is only a wrapper that should hand control to another program.
Examples:
- launching another executable from a setup script
- replacing the current process in deployment scripts
- starting a server process from a small bootstrap script
When to use system
Use system when you want to run a command and only need to know whether it succeeded.
Examples:
- calling
mkdir,cp, orrmin automation scripts - running tests from a Ruby script
- executing a build command and stopping on failure
- invoking CLI tools during deployment
When to use backticks / %x()
Use them when you need the command's output as data.
Examples:
- reading the current Git commit hash
- getting a list of files from a command
- checking the hostname or username
- parsing command-line tool output in a script
branch = `git branch --show-current`.strip
puts "Current branch: "
Real Codebase Usage
In real projects, developers often prefer the method that matches their intent as clearly as possible.
Common patterns
Guard clauses with system
unless system("bundle exec rspec")
abort("Tests failed")
end
This is common in scripts and CI helpers.
Capture and clean output with backticks
ruby_version = `ruby -v`.strip
puts "Running on #{ruby_version}"
.strip is commonly used because command output often ends with a newline.
Bootstrap and handoff with exec
ENV["RACK_ENV"] ||= "production"
exec("bundle exec puma -C config/puma.rb")
This is useful when the current Ruby script should not remain as an extra process.
Exit status handling
Developers often inspect $? after system or backticks.
Common Mistakes
1. Expecting system to return command output
Broken expectation:
files = system("ls")
puts files
files is not the listing. It is usually true or false.
Use backticks instead:
files = `ls`
puts files
2. Expecting code after exec to run
Broken code:
exec("ls")
puts "Done"
If exec works, puts "Done" never runs.
3. Forgetting that backticks include a trailing newline
name = `whoami`
puts name == "alice" # often false
Why? Because name may actually be "alice\n".
Comparisons
| Feature | exec | system | Backticks / %x() |
|---|---|---|---|
| Runs an external command | Yes | Yes | Yes |
| Ruby continues afterward | No, if successful | Yes | Yes |
| Returns command output | No | No | Yes |
| Returns success/failure directly | No | Yes | Not directly |
| Replaces current process | Yes | No | No |
| Useful for scripting flow | Rarely |
Cheat Sheet
Quick reference
exec
exec("ls")
- Replaces the current Ruby process
- Does not return if successful
- Use when handing off execution to another program
system
ok = system("ls")
- Runs command and waits
- Returns
true,false, ornil - Good when you care about success/failure
Backticks / %x()
output = `ls`
output = %x(ls)
- Runs command and captures standard output
- Returns a string
- Good when you need the command result as data
Exit status
system("ls")
puts $?.exitstatus
puts $?.success?
Common rule of thumb
FAQ
Why does Ruby have both system and backticks?
Because they solve different problems. system tells you whether a command succeeded, while backticks give you the command output as a string.
What is the difference between backticks and %x() in Ruby?
There is no meaningful difference in behavior. %x() is just another syntax for command substitution.
Does exec create a new process in Ruby?
exec replaces the current process with the target program. The Ruby program does not continue if exec succeeds.
How do I capture shell command output in Ruby?
Use backticks or %x():
output = `pwd`
How do I check if a shell command succeeded in Ruby?
Use system or inspect $? after running a command:
ok = system("ls")
puts $?.success?
Why is my backtick result ending with ?
Mini Project
Description
Build a small Ruby script that runs a few shell commands in different ways so you can see the difference between system, backticks, and exec in practice. This project is useful because it mirrors real scripting tasks: checking whether commands succeed, capturing output for later use, and handing control off to another program.
Goal
Create a Ruby script that demonstrates success checking with system, output capture with backticks, and process replacement with exec.
Requirements
- Use
systemto run a command and print whether it succeeded. - Use backticks or
%x()to capture command output and display it. - Show the last exit status using
$?. - Use
execat the end so it does not prevent earlier parts of the script from running. - Print clear labels so the behavior of each method is easy to compare.
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.