NAME
Sys::Cmd - run a system command or spawn a system processes
VERSION
0.99.1 (2025-03-28)
SYNOPSIS
# 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->
(
"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 itsSTDOUT
, 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 torun()
above, but without any input handling, output collection, or process waiting; the\%opt
keysinput
,out
anderr
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: - 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()
orspawn()
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
orspawnsub
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 therunsub
method. - spawnsub( @cmd, [\%opt] ) => CODEref
-
Equivalent to manually calling
syscmd(...)
followed by thespawnsub
method.#!perl
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.