Shelling out with backticks
Yesterday we looked at shelling out with system. Another way to shell out in Ruby is by using backticks. When you use backticks, the command is executed in the shell and STDOUT is returned as a string:
`echo Hello, world!`
# => "Hello, world!\n"
`ls non_existent_file`
# ls: non_existent_file: No such file or directory
# => ""
const { execSync } = require("child_process");
execSync("echo Hello, world!", { encoding: "utf-8" });
// => "Hello, world!\n"
let output;
try {
output = execSync("ls non_existent_file", { encoding: "utf-8" });
} catch (error) {
output = "";
}
// ls: non_existent_file: No such file or directory
// => ""
If we want to capture STDERR via backticks, we can redirect it to STDOUT:
`ls non_existent_file 2>&1`
# => "ls: non_existent_file: No such file or directory\n"
Note, however, that doing shell shenanigans like this will not be platform-independent (i.e. it won't work on Windows).
Backticks support interpolation, so you can easily include variables in your commands. However, be cautious since there is no way of avoiding shell injection vulnerabilities when using backticks with user input:
filename = "file.txt"
`cat #{filename}`
# => contents of file.txt
Since backticks are limited to returning STDOUT and don't provide an exit status, they're typically not the first choice for production code, but they are very convenient for simple scripts and IRB doodling.
History
Backtick shelling has been around since Ruby's inception, and the original source of inspiration was command substitution in Unix shells. Perl and PHP also share the same syntax.