Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

IPC::Open3 misbehaving when STDOUT is not FD #1

by sgifford (Prior)
on Jun 05, 2009 at 16:47 UTC ( #768840=perlquestion: print w/ replies, xml ) Need Help??
sgifford has asked for the wisdom of the Perl Monks concerning the following question:

I'm having some trouble with IPC::Open3. Here is a test script that demonstrates the problem:
#!/usr/bin/perl use warnings; use strict; use IPC::Open3; # Basic setup stuff open(SAVE_STDOUT,">&",STDOUT) or die "save stdout failed"; open(DEVNULL,"< /dev/null") or die "open /dev/null failed"; # Now set STDOUT to a filehandle on a new descriptor open(FH1,"> /dev/null") or die "open /dev/null failed"; *STDOUT = *FH1; # Run the command open3(*DEVNULL, *PIPE, undef, "/bin/sh","-c",<<EOF) or die "open3 fail +ed"; printf "out 1\\nout 2\\nout 3\\n" printf "err 1\\nerr 2\\nerr 3\\n" >&2 EOF ; # And copy the output open(STDOUT,">&",*SAVE_STDOUT) or die "restore stout failed"; while (<PIPE>) { print "PIPE: ",$_; } close(PIPE) or die "close pipe failed"; exit(0);
The expected output from this is:
PIPE: out 1 PIPE: out 2 PIPE: out 3 PIPE: err 1 PIPE: err 2 PIPE: err 3
which indicates that the child process had both standard output and standard error sent to the pipe created by open3. Instead, with both IPC::Open3 1.02 and 1.03, I get this output:
out 1 out 2 out 3 PIPE: err 1 PIPE: err 2 PIPE: err 3
This indicates that the standard output from the script didn't go through the pipe. Instead it went directly to my terminal, where file descriptor #1 is connected to in the parent process.

This appears to be the result of a bug in IPC::Open3, which I reported in Perl bug #66224, including a patch. I wanted to see if my fellow Monks had any insight or ideas for a better fix/workaround.

Thanks!

Comment on IPC::Open3 misbehaving when STDOUT is not FD #1
Select or Download Code
Re: IPC::Open3 misbehaving when STDOUT is not FD #1
by Khen1950fx (Canon) on Jun 05, 2009 at 20:35 UTC
    printf "out 1\\nout 2\\nout 3\\n" >&2 will give you the desired output.

    Update: While the answer is true, "true" here means "error". Bash is running printf, not perl, so Bash is running into or and die and returning or: command not found and die: command not found; hence, eveything goes to stderr.

      So will
      #!/usr/bin/perl print <<'__EOI__'; PIPE: out 1 PIPE: out 2 PIPE: out 3 PIPE: err 1 PIPE: err 2 PIPE: err 3 __EOI__

      True, but completely unhelpful.

      I posted my comments to the OP in RT.

      True Khen1950fx, that may be a good workaround. I will see if it works in my environment (it will depend on whether STDERR is set to a file descriptor other than 2, which fails in a similar way). If it does it will be easier to support than a patched IPC::Open3.
Re: IPC::Open3 misbehaving when STDOUT is not FD #1
by ikegami (Pope) on Jun 05, 2009 at 22:34 UTC

    Simpler, clearer, more self-contained test:

    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use Test::More tests => 1; # Hide undesired output. open(STDOUT, '>', '/dev/nul'); open(STDERR, '>', '/dev/nul'); # Associate STDOUT and STDERR with # descriptors other than 1 and 2. open(local *STDOUT, '>', '/dev/nul'); open(local *STDERR, '>', '/dev/nul'); open3( undef, local *PIPE, undef, 'echo out ; echo err >&2', ); my $pipe = ''; $pipe .= $_ while <PIPE>; is($pipe, "out\nerr\n");

    Still unix-specific, though.

      Portable?
      #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use Test::More tests => 1; use File::Spec; my $devnull = File::Spec->devnull; # Hide undesired output. open(STDOUT, '>', $devnull); open(STDERR, '>', $devnull); # Associate STDOUT and STDERR with # descriptors other than 1 and 2. open(local *STDOUT, '>', $devnull); open(local *STDERR, '>', $devnull); open3( undef, local *PIPE, undef, qq!$^X -le "print 111;print STDERR 222"!, ); my $pipe = ''; $pipe .= $_ while <PIPE>; is($pipe, "111\n222\n"); __END__
        $^X isn't properly converted to a shell literal. (i.e. Won't work if there's a space in $^X.) Fix:
        open3( undef, local *PIPE, undef, $^X, q!-le print 111;print STDERR 222!, );
Re: IPC::Open3 misbehaving when STDOUT is not FD #1
by Khen1950fx (Canon) on Jun 07, 2009 at 00:43 UTC
    Admittedly, my first response was on the fly, but I dug deeper and tried this:

    #!/usr/bin/perl use strict; use warnings; use diagnostics; use IPC::Open3; use POSIX 'setsid'; sub daemonize { chdir '/' or die "Can't chdir to /: $!"; open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!"; defined( my $pid = fork ) or die "Can't fork: $!"; exit if $pid; setsid or die "Can't start a new session: $!"; open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; } open( SAVE_STDOUT, ">&", STDOUT ) or die "save stdout failed"; open( DEVNULL, "< /dev/null" ) or die "open /dev/null failed"; open( FH1, "> /dev/null" ) or die "Open /dev/null failed"; &daemonize( *FH1 ); open3( *DEVNULL, *PIPE, undef, "/bin/sh", "-c", <<EOF ); printf "out 1\\nout 2\\nout 3\\n" printf "err 1\\nerr 2\\nerr 3\\n" >&2 EOF ; open( STDOUT, ">&", *SAVE_STDOUT ) or die "restore stdout failed: $!"; while(<PIPE>) { print "PIPE: ", $_; } close(PIPE) or die "close pipe failed"; exit(1);

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (18)
As of 2015-07-01 17:32 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 (14 votes), past polls