Method: Kernel#system

Defined in:
process.c

#system([env,][,options], exception: false) ⇒ true, ...

Executes command… in a subshell. command… is one of following forms.

commandline

command line string which is passed to the standard shell

cmdname, arg1, ...

command name and one or more arguments (no shell)

[cmdname, argv0], arg1, ...

command name, argv[0] and zero or more arguments (no shell)

system returns true if the command gives zero exit status, false for non zero exit status. Returns nil if command execution fails. An error status is available in $?.

If the exception: true argument is passed, the method raises an exception instead of returning false or nil.

The arguments are processed in the same way as for Kernel#spawn.

The hash arguments, env and options, are same as #exec and #spawn. See Kernel#spawn for details.

system("echo *")
system("echo", "*")

produces:

config.h main.rb
*

Error handling:

system("cat nonexistent.txt")
# => false
system("catt nonexistent.txt")
# => nil

system("cat nonexistent.txt", exception: true)
# RuntimeError (Command failed with exit 1: cat)
system("catt nonexistent.txt", exception: true)
# Errno::ENOENT (No such file or directory - catt)

See Kernel#exec for the standard shell.

Returns:

  • (true, false, nil)


4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
# File 'process.c', line 4732

static VALUE
rb_f_system(int argc, VALUE *argv, VALUE _)
{
    /*
     * n.b. using alloca for now to simplify future Thread::Light code
     * when we need to use malloc for non-native Fiber
     */
    struct waitpid_state *w = alloca(sizeof(struct waitpid_state));
    rb_pid_t pid; /* may be different from waitpid_state.pid on exec failure */
    VALUE execarg_obj;
    struct rb_execarg *eargp;
    int exec_errnum;

    execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
    eargp = rb_execarg_get(execarg_obj);
    w->ec = GET_EC();
    waitpid_state_init(w, 0, 0);
    eargp->waitpid_state = w;
    pid = rb_execarg_spawn(execarg_obj, 0, 0);
    exec_errnum = pid < 0 ? errno : 0;

#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
    if (w->pid > 0) {
        /* `pid' (not w->pid) may be < 0 here if execve failed in child */
        if (WAITPID_USE_SIGCHLD) {
            rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
        }
        else {
            waitpid_no_SIGCHLD(w);
        }
        rb_last_status_set(w->status, w->ret);
    }
#endif
    if (w->pid < 0 /* fork failure */ || pid < 0 /* exec failure */) {
        if (eargp->exception) {
            int err = exec_errnum ? exec_errnum : w->errnum;
            VALUE command = eargp->invoke.sh.shell_script;
            RB_GC_GUARD(execarg_obj);
            rb_syserr_fail_str(err, command);
        }
        else {
            return Qnil;
        }
    }
    if (w->status == EXIT_SUCCESS) return Qtrue;
    if (eargp->exception) {
        VALUE command = eargp->invoke.sh.shell_script;
        VALUE str = rb_str_new_cstr("Command failed with");
        rb_str_cat_cstr(pst_message_status(str, w->status), ": ");
        rb_str_append(str, command);
        RB_GC_GUARD(execarg_obj);
        rb_exc_raise(rb_exc_new_str(rb_eRuntimeError, str));
    }
    else {
        return Qfalse;
    }
}