14

I am trying to have STDOUT/STDERR from a exec'ed child process go back to the parent via a pipe in Perl. The closest I have seen to what I want to do is at : http://forums.devshed.com/perl-programming-6/exec-and-redirecting-stdout-stderr-168501.html

The following is a stripped down example of what I am trying to do. I also tried a variant of the link above. I can't see what I'm doing wrong...

#!/usr/bin/env perl

use strict ;
use warnings ;

my $cmd    = "/usr/bin/who -a" ;  # anything to stdout

pipe( READER, WRITER ) ;
my $child = fork() ;
if ( $child ) {
    print "I am the parent: My pid = $$ junior = $child\n" ;
    close( WRITER ) ;
    my @output = <READER> ;
    print @output ;
    print "parent is DONE\n" ;
} else {
    print "I am the child. My pid = $$\n" ;

    close( READER ) ;
    close( STDOUT );
    close( STDERR );
    *STDOUT = *WRITER ;
    *STDERR = *WRITER ;

    print WRITER "XXX ouput before exec....\n" ;

    exec( $cmd ) or exit(1) ;
}
1
  • 2
    You may be interested in IPC::Open2. Commented Aug 18, 2013 at 3:35

3 Answers 3

8

It's not possible to redirect file descriptors just with assignments. Rather one needs to use open like described in perldoc -f open. In your case the child code would look like this:

    print "I am the child. My pid = $$\n" ;

    close( READER ) ;

    open STDOUT, ">&", \*WRITER or die $!;
    open STDERR, ">&", \*WRITER or die $!;

    print WRITER "XXX ouput before exec....\n" ;

    exec( $cmd ) or exit(1) ;
Sign up to request clarification or add additional context in comments.

Comments

8

Slaven Rezic has the right answer to why your code doesn't work, but you should also be aware of a shortcut that you can use. The special pipe+fork open READER, '-|' does almost all the setup work for you, creating a child process with its STDOUT writing into a pipe that the parent can read with READER. That just leaves the STDERR redirection for you to do manually.

The shortened version of the code looks like this:

my $child = open READER, '-|';
defined $child or die "pipe/fork: $!\n";
if ( $child ) {
    print "I am the parent: My pid = $$ junior = $child\n" ;
    my @output = <READER> ;
    print @output ;
    print "parent is DONE\n" ;
} else {
    print "I am the child. My pid = $$\n" ;

    open STDERR, '>&STDOUT';

    print "XXX ouput before exec....\n" ;

    exec( $cmd ) or exit(1) ;
}

Comments

0

This code is another way to pipe the STDOUT and STDERR from the child process.

 #!/usr/bin/env perl
 use strict ;
 use warnings;

 my $cmd    = "/usr/bin/who -a" ;  # anything to stdout

 pipe( READER, WRITER ) ;
 my $child = fork() ;
if ( $child ) {
    print "I am the parent: My pid = $$ junior = $child\n" ;
    close( WRITER ) ;
    my @output = <READER> ;
    print @output ;
    print "parent is DONE\n" ;
} else {
    print "I am the child. My pid = $$\n" ;
    close( READER ) ;
    open(STDERR,">&", WRITER) or die "Cannot duplicate STDERR;
    open(STDOUT,">&", WRITER) or die "cannot duplicate STDOUT";

    print WRITER "XXX ouput before exec....\n" ;

   exec( $cmd ) or exit(1) ;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.