SYNOPSIS

     use Sys::Run::Safer qw(run);
     run(
         prog => 'rm',
         opts => ['-rf', '--interactive=never'],
         args => ['file1', 'file2', 'dir1'],
     ) == 0 or die;

    Will run system('rm', '-rf', '--interactive=never', '--', 'file1',
    'file2', 'dir1'). Upon failure ($? is not zero), will print diagnostic
    error message. Return value is the same as Perl's system().

DESCRIPTION

    Status: experimental, prone to change.

    This module is an experiment to provide a safer API alternative to
    Perl's system() for executing external commands, particularly commands
    that follow the POSIX syntax/GNU extension of accepting command-line
    options/arguments.

    The problem with Perl's system() API is that it may or may not execute
    shell, with relatively complicated rule. Even if you use the list form,
    e.g. system 'cmd', @args it will still use a shell if @args happens to
    be empty. To always avoid the shell you'll have to use the so-called
    third form:  system { 'cmd' } 'cmd', @args which is practically never
    used by casual programmers, including me. Executing shell sometimes is
    desired, but brings many consequences like wildcard/pathname expansion,
    among many other things. You have to be careful to quote every
    input/argument (e.g. using String::ShellQuote).

    This module's run() currently never invokes shell, by using the third
    form of system(). A way to use shell might be provided in the future,
    but will force the programmer to explicitly express so.

    There are other CPAN modules that do this (making it clearer when to
    use shell or not), BTW, e.g. IPC::System::Simple which provides
    additional systemx function which never invokes the shell.

    Another problem that is seldom addressed by other modules is that
    programs can mistakenly interpret argument (e.g. filename) as option if
    that argument happens to start with dash. An example (see [1] for more
    details) is when there is a file named --checkpoint-action=exec=sh
    shell.sh) and you feed it to tar. Even after you avoid shell or quote
    the argument, the filename will still be interpreted as an option (and
    thus the payload shell script executed by tar) unless you precede the
    argument in the command with --. Which is all too easy to be forgotten.

    Thus, the run() API is designed to force you to enter option and
    argument separately, and automatically add a -- after the options.

FAQ

 What about feeding STDIN, capturing STDOUT/STDERR, timeouts, ...?

    I plan to incorporate this API, should the API prove to be not too
    annoying to use, into Proc::Govern. The latter module supports (or
    will/should support) all kinds of child-controlling features.

SEE ALSO

    [1]
    http://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt

    Perl's system() documentation (perldoc -f system).

    There are lots and lots of CPAN modules dealing with running external
    commands. Some offer only improvement/alternative for Perl's system(),
    others provide extra features (from feeding input and capturing output,
    timeout, adding logging/debugging, retry, and so on). I'll limit here
    to listing the modules of the former group:

      * IPC::System::Simple

      Provides a separate function systemx() which never invokes the shell.
      Also provides run() and runx() which dies on failure instead of just
      returning non-zero.

      * IPC::Run

      Recommended over the core IPC::Cmd. IPC::Run's run() won't run shell
      if you feed it arrayref (e.g. run ["ls"] instead of run "ls" even
      though there is only one element in the array (i.e. run ["ls -l"] or
      run ["ls | sort"] won't work). While IPC::Cmd's run will still run
      shell in the latter case, just like Perl's system().

      Note that IPC::Run also has extra features for controlling the child
      process, and is used by some other modules as a backend.