Sys::Run::Safer - Run external commands, with a safer API
This document describes version 0.04 of Sys::Run::Safer (from Perl distribution Sys-Run-Safer), released on 2015-09-06.
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().
system('rm', '-rf', '--interactive=never', '--', 'file1', 'file2', 'dir1')
$?
system()
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).
system 'cmd', @args
@args
system { 'cmd' } 'cmd', @args
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.
run()
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.
systemx
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.
--checkpoint-action=exec=sh shell.sh
tar
--
Thus, the run() API is designed to force you to enter option and argument separately, and automatically add a -- after the options.
Run external commands, with a safer API.
Arguments ('*' denotes required arguments):
args => array[str]
opts => array[str]
prog* => str
Return value: (bool)
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.
[1] http://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt
Perl's system() documentation (perldoc -f system).
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.
systemx()
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().
run ["ls"]
run "ls"
run ["ls -l"]
run ["ls | sort"]
IPC::Cmd
run
Note that IPC::Run also has extra features for controlling the child process, and is used by some other modules as a backend.
Please visit the project's homepage at https://metacpan.org/release/Sys-Run-Safer.
Source repository is at https://github.com/perlancar/perl-Sys-Run-Safer.
Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Sys-Run-Safer
When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.
perlancar <perlancar@cpan.org>
This software is copyright (c) 2015 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Sys::Run::Safer, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Sys::Run::Safer
CPAN shell
perl -MCPAN -e shell install Sys::Run::Safer
For more information on module installation, please visit the detailed CPAN module installation guide.