Shelling out with exec
Another way to shell out in Ruby is by using exec. The exec method replaces the current process with the new command, so on success, it does not return. This means that any code after the exec call will not be executed:
exec "echo Hello, world!"
# Hello, world!
# => (no return value, process is replaced)
puts "This won't be printed"
// Node doesn't have a built-in equivalent to exec and though
// we could implement something similar it would be too verbose
// to implement here 🪦
This can be useful in certain situations, for example, for an entrypoint-type script where you want to run some setup before executing the main command:
# prepare-database-and-run.rb
system("bundle exec rails db:prepare") or exit($?.exitstatus)
exec *ARGV
The exec method has the same argument structure as system, so it also follows that passing multiple arguments to it will avoid shell interpolation.
On Windows the execmethod does not technically replace the current process, since Windows does not have a direct equivalent to the exec system call. Instead, it spawns a new process and terminates the current one, which is similar but not the same.
History
The exec method has been part of Ruby since its inception. It was inspired by the exec system call in Unix-like operating systems, which replaces the current process with a new one.