Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
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 drinking their drinks and smoking their pipes about the Monastery: (7)
As of 2014-08-27 22:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (253 votes), past polls