IPC::System::Simple
released - Cross-platform, multi-arg backticks
One of my greatest itches with Perl is the difficultly in
doing things correctly with the system() command,
which allows one to run a process and wait for it to finish,
and backticks (aka qx()), which allows one to run a
process and capture its output.
It's not that these commands are hard to use.
system("mount /dev/backup") and I've got my backup
media mounted. my $config = qx(ipconfig) and I've
got my Windows IP configuration. They're dead easy to use,
they're just a pain to tell if they worked.
After running, these commands set a special variable named
$?, or $CHILD_ERROR if you've told perl to
use English. This variable is designed to be
"friendly" to "C programmers", who are familiar with the
return value of the wait() system call. But who on
earth wants to be familiar with the return value of
wait()? After teaching thousands of people
Perl over the last seven years, I've only had two
people admit to know what the wait() return value
looks like, and both of them needed therapy afterwards.
It's a packed bit-string, and is grossly unfriendly for
anyone to use in any language.
So, the usual state of affairs for many developers is they
go through their day using system() and backticks
and completely ignoring $?, because it's too hard.
Then one day a disaster happens where they discover that
all their backups are empty, or all their files are
corrupted, or all their furniture has been repossessed,
because their calls to system() have been failing
for years, but nobody noticed because $? was too
ugly to contemplate.
Those developers who have been through this process, or seen
other people's lives ruined usually try to take a little
more care. They recall that $? will be exactly
zero if the process ran to completion and returned a zero
exit status, which usually indicates success. Their code
becomes littered with statements like $? and die $?
or system(...) and die $?. That makes them feel
warm and fuzzy until they discover it doesn't work. Their
command may legitimately return a range of statuses to
indicate success, and a whole bunch of things to indicate
failure. Worse still, printing the contents of $?
as an error message is worse than useless. Nobody
understands what the hell it means; if you did, you wouldn't
be printing it.
The end result of all this is that Perl sucks at something
it's supposed to be good at; namely firing off system
commands and being awesome for system administrators. It is
this problem that IPC::System::Simple
solves.
Put simply, if you're using IPC::System::Simple,
you can replace all your calls to system() with
run(), and all your calls to backticks with
capture(), and it will all work the same way,
except that you'll get incredibly useful messages on error.
Got a funny exit status? It'll tell you what it is, and
the command that caused it. Killed by a signal? You'll get
not just the number, but its name, as well a whether
it dumped core. Passed in tainted data? You'll get told
what was tainted. And it gets better.
Let's say that you're using rsync to backup your
files from an active filesystem. It exits with 0 for good,
and 24 for "files went missing". On an active filesystem,
files disappearing can be considered normal, so we'd like
both of these to be considered 'fine'. Anything else, we'd
like to get told. Can we do this with
IPC::System::Simple? We sure can! Just provide
the list of acceptable exit statuses as the first argument:
run( [0,24], "rsync ....")
IPC::System::Simple's run command also
works the way that the Perl
security pages say that system() should run.
That is, when called with multiple arguments, it bypasses
the shell. Perl's regular system() when called
with multiple arguments will go and use the shell
anyway when on a Windows system, which is bad if you
were trying to avoid shell meta-characters.
You can get the same shell-bypassing behaviour with
capture(); just pass it in multiple arguments and
you're done. This even works under Windows, which normally
doesn't even support shell-bypassing pipes, let alone
checking your command's return values and formatting your
errors afterwards. You even get the full 16-bit Windows
exit value made available to you, which is something
$? and its dark terrors will never give you.
Best of all, installing IPC::System::Simple
is a breeze. It's pure perl, with no dependencies on
non-core modules. Even if you have no other way of
installing modules, you can just copy the .pm file
into an appropriate directory and you're done.
Don't put up with the tragedies and uncertain futures that
system() and backticks can bring. Use IPC::System::Simple
and make handling your system interactions correctly a
painless experience.