Posted over 11 years ago. Visible to the public. Linked content. Deprecated.

Execution of shell code in Ruby scripts

There are countless ways to execute shell code in Ruby. You should always use capture3, for which we have a dedicated card because it is so good.

All other methods to execute shell commands have signficant downsides, such as:

  • They do not tell you if the command has succeeded
  • They only return STDOUT, but not STDERR with error messages
  • They don't let you choose whether command output appears on the screen or not
  • They allow to inject code that will be interpreted by the shell
  • You always need to wait for a long-running process to finish before you can inspect or echo its output

Always use capture3.

Deprecated ways to execute shell code in Ruby

This is just a reference for legacy code. For new code, always use capture3.

%x{ } Archive 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.

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 Archive – 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

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

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 *'

    This is equivalent to:

    $ echo *

    Note how the asterisk is interpreted by the shell, as would any other characters (like a semicolon which separates commands).

    Output will be something like:

    file1 file2 file3
  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', '*'

    This is equivalent to:

    $ /bin/echo '*'

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

    Output will be:


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

This is equivalent to running a command called "bundle exec rails" (including spaces in its filename). There is usually no such command anywhere on the $PATH.

Note that you should prefer the 2nd approach (list of arguments instead of putting them into a single command) unless you absolutely know what you are doing.

exec Archive – 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.

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

spawn Archive – gives you a good level of control

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


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'], '', ''


see the Ruby docs Archive

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 Archive .

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

Owner of this card:

Dominik Schöler
Last edit:
over 3 years ago
by Tobias Kraze
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 makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more