This is a good question. "exec()", "system()", the "%x()" style syntax, and `backticks` all execute system commands from a ruby script. The choice of which one to use will depend on what you're trying to achieve. Here is a quick rundown of each.
system()
# Using the 'system()' command, the evaluated command's output or error is printed to STDOUT or STDERR. The system command must be provided in the form of a string. The return value will be "true" for a successful execution (status code 0), "false" exits with a non-zero status code, or "nil" if the argument is not a recognized command.
> system("whoami")
johnochs
=> true
> system("cat /etc/sudoers")
cat: /etc/sudoers: Permission denied
=> false
> system("lol")
=> nil
# Note that in ruby >= 2.6, there is an optional second argument which controls whether or not to raise an exception if the argument is not a vaild system command.
> system("lol", exception: true)
Errno::ENOENT: No such file or directory - lol
from (pry):76:in `system'
%x()
# Using the "%x()" command syntax will return the command's output as a string. For example, you might use it to do something like the following...
> announcement = "The current date is " + %x(date '+%Y-%m-%d')
> puts announcement
=> "The current date is 2022-10-26"
# Keep in mind that if the command fails (non-zero exit code), an exception will be raised and code execution will stop unless error handling is implemented.
Also, this syntax is not limited to parentheses to enclose the command; %x(date) or %x[date] or %x{date} or %x|date| will all run the system command "date" and return the output as a string.
`backticks`
# Backticks (``) should be used in exactly the same way as the "%x()" syntax; the command will be executed and replaced with the string the command writes to STDOUT or STDERROR. For example...
> message = "This computer's architecture is: " + `arch`
> print message
"This computer's architecture is: arm64
=> nil
# If the command fails (has a non-zero exit code), then an empty string is the return value. If the argument is not a valid command, then an exception will be raised.
exec()
The behavior of exec() is unlike the three previous methods of executing system commands. With a valid command, exec() causes the command provided as its argument to replace the ruby process from which the exec() command is called (i.e. your script or interactive ruby session). If you use exec() in an interactive environment like irb or pry, it will exit to the shell and run the provided command, ending your interactive session and leaving you in the shell.
> puts `ps`
PID TTY TIME CMD
1130 ttys000 0:00.33 -zsh
13428 ttys000 0:00.17 pry
8085 ttys001 0:00.81 -zsh
=> nil
> exec("ps")
PID TTY TIME CMD
1130 ttys000 0:00.33 -zsh
~$
# You can see the interactive ruby process called "pry" (1130) gets replaced by the interactive shell (-zsh) also as process 1130. Note that if an invalid command is given as the argument, a ruby exception is raised and the process is not replaced.
$?
# In ruby, after executing a system command, the global variable "$?" points to an object representing some data about the execution of the last command. Namely, it's process number and it's exit code.
> puts %x(ls -1)
IMG_1096.jpeg
IMG_1098.jpeg
=> nil
> puts $?
=> pid 13733 exit 0