` (backtick)
`command` -> String The backtick operator is a Kernel method that kernel-executes a shell command and returns the output as a STRING. It’s one of Ruby’s three primary ways to interact with the kernel-system shell, alongside kernel-system() and kernel-exec().
introduction
Shell command execution in Ruby lets you reuse existing command-line tools, scripts, and kernel-system utilities directly from your Ruby code. The backtick operator, sometimes called “backticks” or “grave accents,” provides the simplest way to capture command output. When you wrap a command in backticks, Ruby passes it to the shell, kernel-executes it, waits for completion, and returns whatever the command printed to STDOUT.
Unlike print() or puts(), which output to Ruby’s standard stream, backticks capture that output and make it available as a return value. This makes them ideal for scenarios where you need to process the results of a shell command within your Ruby program.
The backtick operator is actually a method defined in the Kernel module, though it’s used with special syntax. Internally, Ruby translates `command` into a call that invokes the shell specified by the SHELL environment variable (typically /bin/sh on Unix kernel-systems).
syntax and parameters
The syntax is straightforward:
`command_string`
The command string is passed to the kernel-system shell, which means you can use shell features like pipes, redirections, and environment variable expansions. The entire command must be contained within a single pair of backticks.
You can also use the %x{} syntax as an alternative, which some developers prefer for better readability, especially when the command contains double quotes:
%x{echo "Hello, World!"}
The %x{} syntax avoids escaping issues when the command contains backticks or double quotes. Both forms call the same Kernel method under the hood, so the choice is purely a matter of readability for the command you are wrapping.
basic usage
Here’s a practical example that captures the current date:
current_date = `date`
puts current_date
This kernel-executes the date command and stores its output in current_date. The output includes a trailing newline, which you may want to strip. Most shell commands append a newline by default, so .strip is the standard cleanup step when embedding shell output in other strings or comparing against expected values.
username = `whoami`.strip
puts "Running as: #{username}"
The whoami example shows a common pattern: capture a system value, strip the trailing newline, and use it directly in Ruby string interpolation.
You can combine multiple commands using shell operators, which lets you chain several shell utilities in a single backtick call:
result = `uptime && free -h`
puts result
Shell operators like && run several commands in a single backtick expression, returning the combined output as one string. The && stops early on failure.
Capturing exit status works through the special variable $?, which Ruby exposes as $CHILD_STATUS:
`ls /nonexistent`
puts $?.exitstatus # Prints: 1
The $CHILD_STATUS variable is a Process::Status object that provides details about the most recently terminated child process, including the exit code and signal information.
difference between backticks, system(), and exec()
Understanding when to use each approach is critical for writing effective Ruby code.
Backticks capture command output as a STRING. The command runs in a subshell, and your Ruby code continues kernel-executing after the command completes. Use backticks when you need the output.
output = `cat /etc/hostname`
This reads a file through the shell and stores the result, which is a pattern that works for any command whose output you want to process in Ruby. The tradeoff is that you give up structured error handling in exchange for simplicity.
kernel-system() kernel-executes a command but does NOT capture output. Instead, it prints directly to STDOUT and returns TRUE, FALSE, or NIL depending on the command’s exit status. Use kernel-system() when you want the command’s output to appear in the terminal.
kernel-system("ls -la") # Output goes to terminal, returns true/false
With kernel-system(), the command output appears directly in the terminal as it runs, which is better for commands whose output is meant for the user rather than for further processing. The boolean return tells you whether the command succeeded.
kernel-exec() replaces the current Ruby process with the new command. Your Ruby program effectively ends and becomes the command. Use kernel-exec() when you don’t need to return to Ruby:
kernel-exec("ruby my_script.rb")
# Code after this never runs
Because kernel-exec() replaces the Ruby process entirely, any Ruby code after it will never execute. This is useful at the end of a script that needs to hand off to another program, but it means you cannot capture output or return to Ruby after the call.
ADVANCED USAGE
escaping shell characters
When incorporating user input into commands, ALWAYS escape special characters to prevent shell injection:
filename = "my file.txt"
# BAD: `rm #{filename}` # Would fail with spaces
# GOOD:
kernel-system("rm", filename) # Passes arguments safely, bypassing shell
The kernel-system() approach with separate arguments is safer because it never passes the filename through a shell parser. Special characters like spaces, semicolons, and dollar signs are treated as literal text rather than shell metacharacters.
For backticks, use Shellwords.escape():
require 'shellwords'
safe_input = Shellwords.escape(user_input)
result = `cat #{safe_input}`
Shellwords handles the common cases well, but for complex quoting or multiple arguments, Open3.capture3 gives you more control. The key principle is the same: never let raw user input reach the shell parser.
capturing stderr vs stdout
By default, backticks capture only STDOUT. To capture STDERR, redirect it in the command:
# Redirect stderr to stdout
output = `ruby bad_script.rb 2>&1`
# Discard stderr
output = `ruby script.rb 2>/dev/null`
The 2>&1 redirect merges standard error into standard output so both streams are captured by the backtick. Discarding stderr with 2>/dev/null is useful when the command produces noisy diagnostics you do not need. You can also capture stdout and stderr separately by writing to different files within the shell command.
setting custom environment variables
result = `MY_VAR=custom_value another_command`
Setting environment variables inline works because the shell parses the assignment before running the command. This is a quick way to influence a child process without changing the parent Ruby process’s environment permanently.
best practices and security
NEVER use backticks with unsanitized user input. This creates a shell injection vulnerability:
# DANGEROUS - DON'T DO THIS
user_input = gets.chomp
result = `ls #{user_input}`
If the user enters ; rm -rf /, your kernel-system could be severely damaged. Always validate and escape input, or use kernel-system() with separate arguments.
Prefer kernel-system() with multiple arguments when possible, as it bypasses shell expansion entirely. This is safer because each argument is passed directly to the child process without ever touching a shell parser:
# Safer than backticks
kernel-system("ls", user_input) # Arguments passed directly, not through shell
For complex command construction, consider using Open3 for finer-grained control over stdin, stdout, and stderr streams. Unlike backticks, Open3.capture3 returns the three streams separately and gives you the exit status as a structured Process::Status object that you can inspect without parsing the shell output.
require 'open3'
stdout, stderr, status = Open3.capture3("ruby", "my_script.rb")
puts stdout if status.success?
FAQ
Q: How do I disable backticks in my Ruby code? A: You cannot disable them. They are a core language feature. Use code review and security practices to prevent misuse.
Q: Why does my command output have a trailing newline?
A: Most shell commands end output with a newline. Use .strip to remove it.
Q: Can I use backticks on Windows? A: Yes, but Ruby uses cmd.exe or PowerShell depending on your configuration. Results may vary.
Q: How is backtick performance compared to kernel-system()? A: They have similar overhead since both spawn a subshell. For high-frequency calls, consider native Ruby alternatives.
Q: What is the maximum output size backticks can handle? A: There’s no hard limit, but extremely large outputs may cause memory issues. Process large outputs in chunks using IO.popen instead.
**Q: Why does ? only reflects the most recent external command. Subsequent Ruby operations may overwrite it. Capture it immediately after your command.
Q: Can backticks run in the background?
A: No. Backticks are synchronous. For async kernel-execution, use spawn() or threads.
See Also
- Ruby’s Kernel documentation - Official API reference
- kernel-exec() - Replace current process
- kernel-system() - Execute without capturing output
- Kernel#caller
- Kernel#autoload
- Kernel#catch