Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Problem with IPC::Open2 when STDOUT/STDERR are redirected

by jeanluca (Deacon)
on Feb 28, 2008 at 12:59 UTC ( [id://670899]=perlquestion: print w/replies, xml ) Need Help??

jeanluca has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks
I have a problem with a module which uses IPC::Open2. Normally this module works but when I wrap it in the following code it doesn't:
my $module = MyModule->new() ; ... my $out = '' ; { local *STDOUT ; local *STDERR ; open (STDOUT,">>", \$out) ; open (STDERR,">>", \$out) ; $module->process() ; } ....
This will make sure that everything printed by $module is redirected to $out.
Here is what's going on in MyModule
use IPC::Open2 ; .... sub process { .. my $pid = open2( *Reader, *Writer, "some_prog" ); print Writer "$some_options" ; my @prog_out = <Reader> ; close Writer; close Reader; .. return @output ; }
Everything printed by some_prog is now redirected to $out and not to @prog_out. Any suggestions how to fix this ?

Cheers
LuCa

ps the main code is part of a cgi script, so I need to catch everything printed by $module, because it is not part of what the users want to see!

Update:sorry tye, you're right. You've said it to me before!! The problem was that there were other modules involved which did things like
print STDOUT "....." ;
I've fixed this and now I can do
open OUT,">>", \$out ; select OUT; $| = 1 ;
Thnx!!

Replies are listed 'Best First'.
Re: Problem with IPC::Open2 when STDOUT/STDERR are redirected (!local)
by tye (Sage) on Feb 28, 2008 at 16:10 UTC

    For the Nth time, don't use local to save/restore file handles, especially the STD* handles. Follow the example in the open documentation for saving and restoring file handles.

    A subprocess will inherit and use file descriptors 0, 1, and 2 from the parent process. local *STDOUT; hides away file descriptor 1 and prevents the process from being able to change it (and prevents Perl from doing its normal extra work when STDOUT is re-opened such that file descriptor 1 would be used).

    Update: s/file handle (\d)/file descriptor $1/g, etc.

    - tye        

      ++tye, for accuracy, but --perl for correctness. The filenos for clib stdin, stdout and stderr should not be hardwired. I recall showing you, a few years ago, how to make stderr have file descriptor 3 on linux and still behave properly there.

      I'm not very up-to-date on either linux or perl at the moment, but I'll check and see if my preferred conventions still hold.

      After Compline,
      Zaxo

        how to make stderr have file descriptor 3 on linux and still behave properly there

        When you fork exec, the only I/O units that the process keeps are the file descriptors. Whatever you have for file descriptor 0 will be stdin/STDIN after exec, no matter what you were using it for and no matter what conventions you set up for how you use it. Whatever your conventions are, they don't change how fork/exec work nor how the process initialization sets up stdin in C (which is what Perl uses to set up its STDIN).

        So if you have conventions that make it so your code will use fd 3 for stderr when you've set it up for that, those have no impact on what the standard process initialization code will do when you fork/exec nor how the child process will set up stderr based on what fd 2 was in the parent process (which will also mean that your code would use fd 2 as stderr when the process is freshly initialized). So your conventions can't "fix" Perl so that, when somebody buries fd 1 with local(*STDOUT) Perl can somehow cause child processes to not use that buried fd 1 as their stdout.

        - tye        

Re: Problem with IPC::Open2 when STDOUT/STDERR are redirected
by pc88mxer (Vicar) on Feb 28, 2008 at 14:20 UTC
    The localization of STDOUT is causing this, but I'm not sure exactly why. Here's code that demonstrates this:

    use strict; use warnings; use IPC::Open2 ; my $out = '' ; { local *STDOUT ; open(STDOUT, ">", \$out); process(); } print "\$out = \n", $out; sub process { my $pid = open2( *Reader, *Writer, "/bin/date" ); my @prog_out = <Reader> ; close Writer; close Reader; print "output from date:\n",join("|", @prog_out), "\n"; }

    This will produce:

    Thu Feb 28 08:08:13 CST 2008 $out = output from date:

    which shows that date printed to the original STDOUT and that the print in the process subroutine printed to $out. If you don't localize STDOUT you get:

    output from date: Thu Feb 28 08:09:54 CST 2008 $out =

    which shows that date emitted its output through the pipe.

    Do you really need to localize STDOUT and STDERR? How about just using select to select a different default file handle? If you need to capture STDERR from your sub-process, how about using IPC::Open3?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-12-07 20:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which IDE have you been most impressed by?













    Results (50 votes). Check out past polls.