Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: STDERR going to string

by Anonymous Monk
on Oct 12, 2011 at 09:27 UTC ( #930947=note: print w/ replies, xml ) Need Help??


in reply to STDERR going to string

You want to use Capture::Tiny, it works on win32, it does it through fork+exec and presents a beautiful interface

use Capture::Tiny 'capture'; my ($out, $err) = capture { print "ya"; Text::BibTeX ... system ... }; print "captured out((($out))) err((($err)))";


Comment on Re: STDERR going to string
Download Code
Re^2: STDERR going to string
by philkime (Sexton) on Oct 13, 2011 at 14:36 UTC
    I tried it - even that doesn't work in this case on windows ...
Re^2: STDERR going to string
by philkime (Sexton) on Oct 15, 2011 at 12:55 UTC
    Here is a simple example showing that even Capture::Tiny doesn't work in this case on Windows.
    #!/usr/bin/perl use Capture::Tiny 'capture'; use File::Temp qw(tempfile); use Inline C; my ($stdout, $stderr) = capture { test_err() }; print "|$stderr|\n"; __END__ __C__ void test_err() { (void)fprintf (stderr, "ERROR"); }

      Here is "proof" perl (or perlxs) is stuffing stderr into a buffer
      #!/usr/bin/perl -- use Inline C => Config => BUILD_NOISY => 1, #~ FORCE_BUILD => 1, CLEAN_AFTER_BUILD => 0, ; # Inline use Inline C => <<'__C__'; void test_err() { PerlIO_printf( PerlIO_stderr(), "Inline::C PerlIO_printf => PerlIO +_stderr()(%p) is PerlIO_fileno()(%d)\n", PerlIO_stderr(), PerlIO_file +no(PerlIO_stderr()) ); fprintf (stderr, "Inline::C fprintf => PerlIO_stderr()(%p) is Perl +IO_fileno()(%d)\n", PerlIO_stderr(), PerlIO_fileno(PerlIO_stderr()) ) +; fprintf (stderr, "Inline::C fprintf => stderr(%p) is fileno(%d)\n" +, stderr, fileno(stderr) ); // above output gets eaten if you flush // fflush (stderr ); fprintf (stderr, "will somebody please eat my stderr buffer \n"); } __C__ Main( @ARGV ); print "main is over\n"; exit( 0 ); END { print "perl is over\n"; } sub Main { use FileHandle; STDERR->autoflush(1); STDOUT->autoflush(1); use File::Temp qw' tempfile '; open my $olderr, '>&STDERR'; # save STDERR my ($fh, $fn) = tempfile(); open STDERR, '>&', $fh; test_err(); open STDERR, '>&', $olderr; # reset STDERR close $fh; open my $e, '<', $fn; my $err = <$e>; print "(((($err))))\n"; } __END__

      without fflush

      ((((Inline::C PerlIO_printf => PerlIO_stderr()(99417c) is PerlIO_filen +o()(2) )))) main is over perl is over Inline::C fprintf => PerlIO_stderr()(0099417C) is PerlIO_fileno()(2) Inline::C fprintf => stderr(77C5FCC0) is fileno(2) will somebody please eat my stderr buffer

      with fflush

      ((((Inline::C PerlIO_printf => PerlIO_stderr()(99417c) is PerlIO_filen +o()(2) )))) main is over perl is over will somebody please eat my stderr buffer

      And doing the same thing WITHOUT perl , code from _dup, _dup2 adapted for mingw-gcc

      // crt_dup.c // This program uses the variable old to save // the original stdout. It then opens a new file named // DataFile and forces stdout to refer to it. Finally, it // restores stdout to its original state. // #include <io.h> #include <stdlib.h> #include <stdio.h> int main( void ) { int old; FILE *DataFile; old = _dup( 1 ); // "old" now refers to "stdout" // Note: file descriptor 1 == "stdout" if( old == -1 ) { perror( "_dup( 1 ) failure" ); exit( 1 ); } _write( old, "This goes to stdout first\n", 26 ); if( fopen_s( &DataFile, "data", "w" ) != 0 ) { puts( "Can't open file 'data'\n" ); exit( 1 ); } // stdout now refers to file "data" if( -1 == _dup2( _fileno( DataFile ), 1 ) ) { perror( "Can't _dup2 stdout" ); exit( 1 ); } puts( "This goes to file 'data'\n" ); system( "echo echo echo echo echo echo echo" ); system( "echo echo this goes to 'data' " ); system( "perl -le print(666)" ); // goes to data // Flush stdout stream buffer so it goes to correct file fflush( stdout ); fclose( DataFile ); // Restore original stdout _dup2( old, 1 ); puts( "This goes to stdout also\n" ); puts( "The file 'data' contains:" ); _flushall(); system( "type data" ); } //~ EUREKA http://v8.googlecode.com/svn/trunk/src/platform-win32.cc int fopen_s(FILE** pFile, const char* filename, const char* mode) { *pFile = fopen(filename, mode); return *pFile != NULL ? 0 : 1; }

      as you can see it works

      This goes to stdout first This goes to stdout also The file 'data' contains: echo echo echo echo echo echo echo this goes to 'data' 666 This goes to file 'data'

      If I knew more about gcc and debuggers, I might try to figure out WHERE perl fudges things , but I don't :)

      I'm embarrassed. Someone pointed out to me that Windows doesn't flush STDERR as often as other OSES. With one extra line of C, it works on Windows and I think I can modify the external library this much ...
      #!/usr/bin/perl use Capture::Tiny 'capture'; use File::Temp qw(tempfile); use Inline C; my ($stdout, $stderr) = capture { test_err() }; print "|$stderr|\n"; __END__ __C__ void test_err() { (void)fprintf (stderr, "ERROR"); (void)fflush(stderr); }

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2015-07-05 07:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (60 votes), past polls