Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Can't capture STDERR to Variable

by Skeeve (Vicar)
on Jul 21, 2011 at 10:11 UTC ( #915822=perlquestion: print w/ replies, xml ) Need Help??
Skeeve has asked for the wisdom of the Perl Monks concerning the following question:

Maybe it's something very obvious to anyone but me? ;)

I want to analyze an external program's STDOUT and STDERR and don't like to redirect STDERR to a file which I later have to read, and delete.

So I thought I'd redirect STDERR to a variable like this:

close STDERR; open STDERR,">",\$x or die; `ls /some/nonexisting/path`; print $x;

I expected $x to read "/some/nonexisting/path: No such file or directory" but it's simply empty.

Does anyone of you see what's wrong and can give me a hint?


s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
+.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

Comment on Can't capture STDERR to Variable
Select or Download Code
Re: Can't capture STDERR to Variable
by moritz (Cardinal) on Jul 21, 2011 at 10:18 UTC
Re: Can't capture STDERR to Variable
by salva (Monsignor) on Jul 21, 2011 at 10:21 UTC
    Use Capture::Tiny or some other similar module.

    File handles opened to scalar references can not be used outside the Perl process where they were created (and even then, most modules wrapping external C libraries will also fail to recognize them as valid file handles).

Re: Can't capture STDERR to Variable
by davido (Archbishop) on Jul 21, 2011 at 10:22 UTC

    qx// and the backticks operator don't capture STDERR. There's a discussion of this in perlop (the preceding link is anchored to the relevant section). The docs do provide some examples of how to finesse STDERR to do what you want.


    Dave

Re: Can't capture STDERR to Variable
by zentara (Archbishop) on Jul 21, 2011 at 11:41 UTC
    Here is a general purpose example using IPC::Open3. You can run your exact command, instead of bash in the example.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use IO::Select; my $pid = open3(\*WRITE, \*READ,\*ERROR,"/bin/bash"); my $sel = new IO::Select(); $sel->add(\*READ); $sel->add(\*ERROR); my($error,$answer)=('',''); while(1){ print "Enter command\n"; chomp(my $query = <STDIN>); #send query to bash print WRITE "$query\n"; foreach my $h ($sel->can_read) { my $buf = ''; if ($h eq \*ERROR) { sysread(ERROR,$buf,4096); if($buf){print "ERROR-> $buf\n"} } else { sysread(READ,$buf,4096); if($buf){print "$query = $buf\n"} } } } waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created.

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh

      open3 is a pretty low-level tool. It does some things quite well, but this isn't one of them. See instead: IPC::Run3, IPC::Run

      PS — Your code has a race condition that could deadlock both processes since you only passed two of the three handles to select.

Re: Can't capture STDERR to Variable
by Skeeve (Vicar) on Jul 22, 2011 at 07:11 UTC

    Thanks to all of you!

    Capture::Tiny looks promising and I will consider it for a rewrite of my script.

    For my task at hand, merging STDOUT and STDERR with "2>&1" is sufficient, but I don't like it as a "solution". I think it is just a workaround.

    And to answer moritz' Question: Yes! ls is just an example. The real program I call is openssl.


    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://915822]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2014-09-17 05:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (58 votes), past polls