You want full control over a command's input, output, and error streams.
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.)
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 buffers are full, and you will block on the read because there's nothing available.
You can avoid this deadlock by mimicking
open3
with
fork
,
open
, and
exec
; making all the filehandles unbuffered; and using
sysread
,
syswrite
, and
select
to decide which readable filehandle to read a byte from. This makes your program slower and bulkier, though, and it doesn't solve the classic
open2
deadlock where each program is expecting the other to say something.
use IPC::Open3; $pid = open3(*HIS_IN, *HIS_OUT, *HIS_ERR, $cmd); close(HIS_IN); # give end of file to kid, or feed him @outlines = <HIS_OUT>; # read till EOF @errlines = <HIS_ERR>; # XXX: block potential if massive print "STDOUT:\n", @outlines, "\n"; print "STDERR:\n", @errlines, "\n";
As if deadlock weren't bad enough, this approach is subtly error-prone. There are at least three worrisome situations: both the child and the parent trying to read at the same time, causing deadlock; full buffers causing the child to block as it tries to write to STDERR while the parent is blocked trying to read from the child's STDOUT; and full buffers causing the parent to block writing to the child's STDIN while the child is blocked writing to either its STDOUT or STDERR. The first problem is generally unsolvable, although you can work around it by setting timers with
alarm
and preventing blocking operations from restarting if a
SIGALRM
is received.
We use the
IO::Select module (you could also do this with the built-in function
select
) to learn which filehandles (if any) can be read from. This solves the second problem, but not the third. To solve the third, you also need
alarm
and non-restarting
SIGALRM
.
If you want to send input to the program, read its output, and either read or ignore its error, you need to work much harder. (See Example 16.2 .)
#!/usr/bin/perl # cmd3sel - control all three of kids in, out, and error. use IPC::Open3; use IO::Select; $cmd = "grep vt33 /none/such - /etc/termcap"; $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd); $SIG{CHLD} = sub { print "REAPER: status $? on $pid\n" if waitpid($pid, 0) > 0 }; print CMD_IN "This line has a vt33 lurking in it\n"; close(CMD_IN); $selector = IO::Select->new(); $selector->add(*CMD_ERR, *CMD_OUT); while (@ready = $selector->can_read) { foreach $fh (@ready) { if (fileno($fh) == fileno(CMD_ERR)) {print "STDERR: ", scalar <CMD_ERR>} else {print "STDOUT: ", scalar <CMD_OUT>} $selector->remove($fh) if eof($fh); } } close(CMD_OUT); close(CMD_ERR);
We sent only a short line as input, then closed the handle. This avoids the deadlock situation of two processes each waiting for the other to write something.
The documentation for the standard IO::Select, IPC::Open2, and IPC::Open3 modules; the
alarm
function in
Chapter 3
of
Programming Perl
or
perlfunc
(1);
Recipe 16.8
;
Recipe 16.15
;
Recipe 16.16
16.8. Controlling Input and Output of Another Program | 16.10. Communicating Between Related Processes |
Copyright © 2001 O'Reilly & Associates. All rights reserved.