http://www.perlmonks.org?node_id=520085


in reply to Capturing stderr

Is it enough to merge the stdout together with the stderr into one stream? If so then you could do

$output = `$cmd 2>&1`
It sounds like you want to capture the stdout and stderr into seperate variables though. You will need this:
use strict; use IO::Select; use POSIX; pipe(STDOUT_READ, STDOUT_WRITE) || die; pipe(STDERR_READ, STDERR_WRITE) || die; my $pid = fork(); die unless (defined($pid)); if ($pid == 0) { close STDOUT_READ; close STDERR_READ; open(STDOUT, ">&STDOUT_WRITE"); open(STDERR, ">&STDERR_WRITE"); close STDOUT_WRITE; close STDERR_WRITE; exec $cmd; POSIX::_exit(1); } my $stdout_collected = ""; my $stderr_collected = ""; close STDOUT_WRITE; close STDERR_WRITE; my $sel = IO::Select->new(); $sel->add(\*STDOUT_READ); $sel->add(\*STDERR_READ); my $remaining = 2; while ($remaining > 0) { my @ready = $sel->can_read(); for my $r (@ready) { my $got; if (sysread($r, $got, 1024) == 0) { close $r; $remaining--; } ($r == \*STDOUT_READ) ? $stdout_collected : $stderr_collected .= $got; } } undef $sel; waitpid $pid, 0; # stdout is collected in $stdout_collected # stderr is collected in $stderr_collected

Update: Changed read to sysread

Replies are listed 'Best First'.
Re^2: Capturing stderr
by Zadeh (Beadle) on Dec 30, 2005 at 23:48 UTC
    Yeah, I'd like to capture them separately. That looks pretty involved though... seems like there should be a simpler way. I'll try that for now though, thanks.
      I once asked a similar question in Redirecting stdout/stderr to pipe. Thelonius described a method in (Re: Redirecting stdout/stderr to pipe) that captures stdout as well as stderr (seperately) to array references (see the @$outref and @$errref portions of the code).

      The code also includes detection of commands that have been running for too long or when the array's output size exceeds $g_maxlines lines.

      0xbeef

Re^2: Capturing stderr
by jthalhammer (Friar) on Dec 31, 2005 at 03:04 UTC
    That looks painful. Is there any reason that IPC::Open3 wouldn't work?

    -Jeff

      IPC::Open3 will indeed simplify the first half of the code, which deals with the piping and the forking. Sorry for recommending the long winded solution :-( . It won't help with reading the outputs afterwards though, you still have to use a select loop to read interleaved input from both handles. That's why [id://ikegami]'s recommentation of IPC::Run looks like it's even easier (thanks!).