Posted over 5 years ago. Visible to the public. Repeats.

Execution of shell code in Ruby scripts

There are several ways to execute shell code in Ruby. Spawn is the method behing exec, system and %x[…], don't use it, but check the documentation below.

%x{ } or backticks – quick and easy

Returns the standard output of running the given command in a subshell. This is an alias for `…`, and you can use string interpolation.

Example:

name = 'ls' result = `which #{name}`

It does not escape anything you inject in the string.

If you want to find out if the call was successful you can ask $?.success?.

system – when you want to know how it went

Similar to exec, but executes the given command in a subshell. Your script will go on. Returns:

  • true if the command gives zero exit status
  • false for non zero exit status

Example:

if system 'cp', '/full/path/to/my_file', '/target/directory' puts "You made it!" else puts "Something went wrong" end

Note that system (as well as exec) has two distinct argument patterns:

  1. a single string argument is passed to the shell like "Hey, lets pretend the user typed this. Please run it!"

    system 'echo *' # equivalent $> echo *
  2. when passed multiple arguments, Ruby will take the first as command and find it on the $PATH. It then invokes it, passing the remaining arguments as Strings:

    system 'echo', '*' # equivalent $> /bin/echo '*'

    Since Ruby is passing all arguments as Strings, there will be no wildcard expansion or the like.

You cannot freely mix these styles, and system will fail when passing it invalid arguments:

system 'bundle exec rails server', '-p 3000' # fails and returns nil # equivalent # There is no command named 'bundle exec rails' anywhere on the $PATH

You need to comply with either of the two arguments patterns: Either run system 'bundle exec rails server -p 3000' or system 'bundle', 'exec', 'rails', 'server', '-p', '3000'.

exec – the last thing you do

Replaces the current process. Take care: when an exec command exits, it exits your script as well; i.e. exec will be the last statement executed in your Ruby script. Output is written to stdout.

Raises SystemCallError if the command couldn‘t execute.

Example:

puts "Creating directory..." exec 'mkdir', 'new_directory' # the code here and below will never be read

spawn – gives you a good level of control

Takes the same parameters as exec and system: [env,] command [,options]

env
Optional hash with :name => environment_name, e.g. spawn(:name => 'development', 'echo hello world')
command, either:
  • A single string which is passed to the standard shell (with shell expansion), e.g. exec('cat * | grep denied')
  • The command name and one or more plain arguments (without shell expansion), e.g. exec *[ 'git', 'add', 'Gemfile' ]
    If the first command is a two-element array, the first element is taken as the command to be executed, and the second argument is used as the argv[0] value, which may show up in process listings. E.g. exec ['ls', 'foo'], 'foo.bar', 'baz.bar'
options
see the Ruby docs

The shell used is /bin/sh on Unix-like systems, ENV["RUBYSHELL"] or ENV["COMSPEC"] on Windows NT series, and similar.

Spawn calls IO.popen.

open3 – for those who want to control everything

"Open3 grants you access to stdin, stdout, stderr and a thread to wait the child process when running another program. You can specify various attributes, redirections, current directory, etc., of the program as Process.spawn." Quoted from the docs

Use open3 when you have to explicitly manage all input, output, and errors.

Does your version of Ruby on Rails still receive security updates?
Rails LTS provides security patches for old versions of Ruby on Rails (3.2 and 2.3).

Author of this card:

Avatar
Dominik Schöler
Last edit:
3 days ago
by Dominik Schöler
Keywords:
command, line, parameters, arguments, cli, bash
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Dominik Schöler to makandropedia