The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

NAME

Sys::Cmd - run a system command or spawn a system processes

VERSION

0.99.1 (2025-03-28)

SYNOPSIS

use Sys::Cmd qw/run spawn/;
# Simplest scenario:
# - returns standard output
# - warns about standard error
# - raises exception on failure
$output = run(@cmd);
# Alternative input / output:
# - returns standard output lines
# - after feeding its standard input
@output = run( @cmd, { input => 'food' } );
# More flexibility:
# - Run in alternative directory
# - With a modified environment
# - Capturing stdout/stderr into variables
run(
@cmd,
{
dir => '/',
env => { SECRET => $pass },
out => \$out,
err => \$err,
}
);
# Spawn a process for asynchronous interaction
# - Caller responsible for exec path, all input & output
# - No exception raised on non-zero exit
$proc = spawn( @cmd, { encoding => 'iso-8859-3' },);
while ( my $line = $proc->stdout->getline ) {
$proc->stdin->print("thanks\n");
}
my @errors = $proc->stderr->getlines;
$proc->close(); # Finished talking to file handles
$proc->wait_child(); # Cleanup
# read process termination information
$proc->exit(); # exit status
$proc->signal(); # signal
$proc->core(); # core dumped? (boolean)

DESCRIPTION

Sys::Cmd lets you run system commands and capture their output, or spawn and interact with a system process through its STDIN, STDOUT, and STDERR file handles.

It also provides mock process support, where the caller defines their own outputs and error values. Log::Any is used for logging.

The following functions are exported on demand:

run( @cmd, [\%opt] ) => $output | @output

Execute @cmd and return what the command sends to its STDOUT, raising an exception in the event of non-zero exit value. In array context returns a list of lines instead of a scalar string.

The first element of @cmd determines what/how things are run:

  • If it has a path component (absolute or relative) it is executed as is, using Proc::Spawn.

  • If it is a CODE reference (subroutine) then the funtion forks before running it in a child process. Unsupported on Win32.

  • Everything else is looked up using File::Which and the result is executed with Proc::Spawn.

The optional \%opts hashref lets you modify the execution via the following configuration keys (=> default):

dir => $PWD

The working directory the command will be run in. Note that if @cmd is a relative path, it may not be found from the new location.

encoding => $Encode::Locale::ENCODING_LOCALE

A string value identifying the encoding that applies to input/output file-handles, command arguments, and environment variables. Defaults to the 'locale' alias from Encode::Locale.

env

A hashref containing key/values to be added to the current environment at run-time. If a key has an undefined value then the key is removed from the environment altogether.

input

A scalar (string), or ARRAY reference, which is fed to the command via its standard input, which is then closed. An empty value ('') or empty list will close the command's standard input without printing. An undefined value (the default) leaves the handle open.

Some commands close their standard input on startup, which causes a SIGPIPE when trying to write to it, for which Sys::Cmd will warn.

mock

A subroutine reference which runs instead of the actual command, which provides the fake outputs and exit values. See "MOCKING" below for details.

out

A reference to a scalar which is populated with output. When used, run() returns nothing.

err

A reference to a scalar which is populated with error output. When used, run() does not warn of errors.

on_exit

A subref to be called at the time that process termination is detected.

spawn( @cmd, [\%opt] ) => Sys::Cmd::Process

Executes @cmd, similarly to run() above, but without any input handling, output collection, or process waiting; the \%opt keys input, out and err keys are invalid for this function.

This returns a (Sys::Cmd::Process) object representing the running process, which has the following methods:

cmdline() => @list | $str

In array context returns a list of the command and its arguments. In scalar context returns a string of the command and its arguments joined together by spaces.

close()

Close all filehandles to the child process. Note that file handles will automaticaly be closed when the Sys::Cmd object is destroyed. Annoyingly, this means that in the following example $fh will be closed when you tried to use it:

my $fh = Sys::Cmd->new( %args )->stdout;

So you have to keep track of the Sys::Cmd object manually.

pid()

The command's process ID.

stderr()

The command's STDERR file handle, based on IO::Handle so you can call getline() etc methods on it.

stdin()

The command's STDIN file handle, based on IO::Handle so you can call print() etc methods on it. Autoflush is automatically enabled on this handle.

stdout()

The command's STDOUT file handle, based on IO::Handle so you can call getline() etc methods on it.

wait_child() -> $exit_value

Wait for the child to exit using waitpid, collect the exit status and return it. This method sets the exit, signal and core attributes and is called automatically when the Sys::Cmd::Process object is destroyed.

After wait_child has been called the following are also valid:

core()

A boolean indicating the process core was dumped.

exit()

The command's exit value, shifted by 8 (see "perldoc -f system").

signal()

The signal number (if any) that terminated the command, bitwise-added with 127 (see "perldoc -f system").

syscmd( @cmd, [\%opt] ) => Sys::Cmd

When calling a command multiple times, possibly with different arguments or environments, a kind of "templating" mechanism can be useful, to avoid repeatedly specifying configuration values and wearing a path lookup penalty each call.

A Sys::Cmd object represents a command (or coderef) to be executed, which you can create with the syscmd function:

my $git = syscmd('git',
env => {
GIT_AUTHOR_NAME => 'Geekette',
GIT_AUTHOR_EMAIL => 'xyz@example.com',
}
);

You can then repeatedly call run() or spawn() methods on the object for the actual work. The methods work the same way in terms of input, output, and return values as the exported package functions. However, additional arguments and options are merged:

my @list = $git->run('ls-files'); # $PWD
my $commit = $git->run( 'commit', {
env => { GIT_AUTHOR_NAME => 'Sysgeek' }
});

For even less syntax you can use the runsub or spawnsub methods to get a subroutine you can call directly:

my $git = syscmd('git')->runsub;
my @list = $git->('ls-files');
my $commit = $git->('show');
runsub( @cmd, [\%opt] ) => CODEref

Equivalent to manually calling syscmd(...) followed by the runsub method.

#!perl
use Sys::Cmd 'runsub';
my $ls = runsub('ls');
$ls->('here');
$ls->('there');
spawnsub( @cmd, [\%opt] ) => CODEref

Equivalent to manually calling syscmd(...) followed by the spawnsub method.

#!perl
use Sys::Cmd 'spawnsub';
my $spawn = spawnsub('command');
foreach my $i (0..9) {
my $proc = $spawn->('arg', $i);
$proc->stdin->print("Hello\n");
print $proc->stdout->getlines;
$proc->wait_child
}

MOCKING (EXPERIMENTAL!)

The mock subroutine, when given, runs instead of the command line process. It is passed the Sys::Cmd::Process object as its first argument, which gives it access to the cmdline, dir, env, encoding, attributes as methods.

run(
'junk',
{
input => 'food',
mock => sub {
my $proc = shift;
my $input = shift;
[ $proc->cmdline . ":Thanks for $input!\n", '', 0 ];
}
}
);

It is required to return an ARRAY reference (possibly empty), with the following elements:

[
"standard output\n", # default ''
"standard error\n", # default ''
$exit, # default 0
$signal, # default 0
$core, # default 0
]

Those values are then returned from run as usual. At present this feature is not useful for interactive (i.e. spawned) use, as it does not dynamically respond to calls to $proc-stdin->print()>.

Note that this interface is EXPERIMENTAL and subject to change! Don't use it anywhere you can't deal with breakage!

ALTERNATIVES

AnyEvent::Run, AnyEvent::Util, Argv, Capture::Tiny, Child, Forks::Super, IO::Pipe, IPC::Capture, IPC::Cmd, IPC::Command::Multiplex, IPC::Exe, IPC::Open3, IPC::Open3::Simple, IPC::Run, IPC::Run3, IPC::RunSession::Simple, IPC::ShellCmd, IPC::System::Simple, POE::Pipe::TwoWay, Proc::Background, Proc::Fork, Proc::Spawn, Spawn::Safe, System::Command

SUPPORT

This distribution is managed via github:

This distribution follows the semantic versioning model:

Code is tidied up on Git commit using githook-perltidy:

AUTHOR

Mark Lawrence <mark@rekudos.net>, based heavily on Git::Repository::Command by Philippe Bruhat (BooK).

COPYRIGHT AND LICENSE

Copyright 2011-2025 Mark Lawrence <nomad@null.net>

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.