How to call shell commands from Ruby?
Ruby offers multiple ways to call shell commands—whether you need to list files, run scripts, or integrate with system tools. The language provides clean, concise APIs for capturing outputs, handling errors, and interacting with the command’s input/output streams. Below, we explore the most common methods for executing shell commands in Ruby, along with best practices to keep your code robust and secure.
1. Using Backticks
The simplest way to execute a shell command in Ruby is by using backticks (``):
output = `ls`
puts output
- Returns a String: Backticks execute the command in a subshell, capturing whatever is printed to
stdout. - Easy to Use: Ideal for quick scripts that need to grab text output.
- Security Note: Be careful not to pass unsafe user input into the backticks directly—this can expose you to shell injection attacks.
2. Using the %x Literal
Ruby also provides an alternate syntax using %x{}:
output = %x{echo "Hello from Ruby!"}
puts output
- Same Behavior as Backticks:
%xis functionally equivalent to using backticks, making it another handy option if your command needs quotes or includes backticks of its own.
3. Using system
Use system if you only need to run a command and check its success without capturing the output:
success = system("echo 'Running system command'")
puts success # => true or false
- Boolean Return: Returns
trueif the command executes successfully,falseotherwise. - Exit Status: You can also inspect
$?(an instance ofProcess::Status) to see the exact exit code.
4. Using exec
When you call exec, Ruby immediately replaces the current process with the specified command:
exec("echo 'This will replace the Ruby process'")
puts "This will never run."
- No Return:
execdoes not come back to the Ruby script. Once called, your script’s execution ends and transfers control to the external command. - Use Sparingly: Ideal in cases where you truly need to switch processes, such as launching a different program.
5. Using Open3 for Advanced Control
For more complex use cases—where you might need to capture both stdout and stderr, or feed data interactively—use the Open3 module:
require 'open3'
stdout, stderr, status = Open3.capture3("ls -la")
if status.success?
puts "STDOUT:\n#{stdout}"
else
puts "STDERR:\n#{stderr}"
end
- Capture Streams:
capture3returns standard output, standard error, and the exit status. - Real-Time Interaction: For even more control (writing to
stdinor reading output as it arrives), useOpen3.popen3.
Best Practices
- Sanitize User Input: Always validate or escape external input passed to shell commands to prevent injection attacks.
- Check Exit Codes: Use
$?or the status object fromOpen3to verify whether a command completed successfully. - Choose the Right Tool:
- Backticks /
%xfor quick, one-off commands where you need the output. systemwhen you only care about success/failure.execif you want to replace the current process.Open3for more advanced needs, like interactive I/O or capturing error streams.
- Backticks /
Recommended Courses to Strengthen Your Skills
Grokking the Coding Interview: Patterns for Coding Questions
Ideal for mastering core coding patterns that top tech companies often test.Grokking System Design Fundamentals
A beginner-friendly approach to understanding the basics of large-scale, distributed systems.Grokking the System Design Interview
Perfect for developers preparing for system design interviews at FAANG and other leading tech companies.
If you’re looking for a free primer or additional resources, check out the System Design Primer: The Ultimate Guide on the DesignGurus.io blog. You can also consider Coding Mock Interview or System Design Mock Interview sessions to get personalized feedback from ex-FAANG engineers.
Conclusion
Ruby makes it exceptionally straightforward to call shell commands—from simple one-liners using backticks or %x, to more advanced features using Open3. Which method you choose depends on your project’s needs, but always remember to safeguard against security pitfalls and handle errors correctly. Combine these practices with robust coding and system design skills, and you’ll be ready to tackle both day-to-day scripting tasks and high-level software engineering challenges with confidence.
Recommended Courses