Controlling the Input, Output, and Error of Another Program

Problem

You want full control over a command’s input, output, and error streams.

Solution

Carefully use the standard IPC::Open3 module, possibly in conjunction with the IO::Select module. (IO::Select is new as of the 5.004 distribution.)

Discussion

If you’re interested in only one of the program’s STDIN, STDOUT, or STDERR, the task is simple. When you want to manage two or more of these, however, it abruptly stops being simple. Multiplexing multiple I/O streams is never a pretty picture. Here’s an easy workaround:

@all = `($cmd | sed -e 's/^/stdout: /' ) 2>&1`;
for (@all) { push @{ s/stdout: // ? \@outlines : \@errlines }, $_ }
print "STDOUT:\n", @outlines, "\n";
print "STDERR:\n", @errlines, "\n";

If you don’t have sed on your system, you’ll find that for simple cases like this, perl -pe works just as well as sed -e.

However, that’s not really simultaneous processing. All we’re doing is marking STDOUT lines with "stdout:" and then stripping them back out once we’ve read all the STDOUT and STDERR the program produced.

You can use the standard IPC::Open3 module for this. Mysteriously, the argument order is different for IPC::Open3 than for IPC::Open2.

open3(*WRITEHANDLE, *READHANDLE, *ERRHANDLE, "program to run");

Using this has even more potential for chaos than using open2. If you’re reading the program’s STDERR as it is trying to write more than one buffer’s worth to its STDOUT, the program will block on the write because its ...

Get Perl Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.