Execute System Commands in Ruby
There are several ways to invoke system commands in Ruby:
- Backquotes `` or
- The open3 lib
Backquotes and system methods
The difference between backquotes and
system is that:
system only returns true/false; while
%x returns the stdout of the command when the command execution succeeds, and an empty string
"" when the command fails.
r = `ls` => "Dockerfile\nGemfile\nGemfile.lock..." r = `cat NoFile` cat: NoFile: No such file or directory => "" system("ls") Dockerfile Jenkinsfile bin => true system("cat NoFile") cat: NoFile: No such file or directory => false
So it seems that the backquotes or
%x() work better. When do you need to use
system? My experience is that when you need to execute an interactive console,
system is more convenient.
`rails console` # get blocked system 'rails console' [Patch] Preventing bunny channel leaks Loading development environment (Rails 6.0.0)  pry(main)> exit => true
There is no way to get the STDERR of the command, either backquote or system, so you can use Ruby's
Open3 standard library, of which
Open3.capture3 is a very good way to use it.
require 'open3' => true # When everything goes right stdout, stderr, status = Open3.capture3('ls') => ["Dockerfile\nGemfile\nGemfile.lock... \n", "", #<Process::Status: pid 60368 exit 0>] status => #<Process::Status: pid 60368 exit 0> status.exitstatus => 0 # When something goes wrong stdout, stderr, status = Open3.capture3('cat NOTHING') => ["", "cat: NOTHING: No such file or directory\n", #<Process::Status: pid 60385 exit 1>] stderr => "cat: NOTHING: No such file or directory\n" status => #<Process::Status: pid 60385 exit 1>
Exit Code and Run Result
In the shell there is a variable
$? that marks the exit code of the last command:
$ ls -alt total 328 -rw-r--r-- 1 xiao.wang staff 927B Sep 17 14:18 Dockerfile ... $ echo $? 0 $ cat NOTHING cat: NOTHING: No such file or directory $ echo $? 1
By convention, the exit code is 0 when the command is executed successfully, and a number other than 0 when it fails.
There is no absolute standard for this number, but there are some conventions: FreeBSD agrees on a larger number of exit codes: http://www.freebsd.org/cgi/man.cgi?query=sysexits&sektion=3 GNU is relatively simple: http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
In Ruby, there is a global variable with the same name as in the shell
system('echo Hello') Hello => true $? => #<Process::Status: pid 60633 exit 0> $? .exitstatus => 0
It is also possible to load the
English standard library to make this variable more readable:
require 'English' => true 2.6.3 :020 > system('echo 1') 1 $CHILD_STATUS => #<Process::Status: pid 60659 exit 0> $CHILD_STATUS.exitstatus.zero? => true