How to read to and write from a pipe in perl with

2019-09-05 16:52发布

问题:

This excellent question How to read to and write from a pipe in Perl? provides an excellent answer.

It doesn't work on ActiveState Perl.

The BUGS section of perlfork http://docs.activestate.com/activeperl/5.14/lib/pods/perlfork.html says

In certain cases, the OS-level handles created by the pipe(), socket(), and accept() operators are apparently not duplicated accurately in pseudo-processes. This only happens in some situations, but where it does happen, it may result in deadlocks between the read and write ends of pipe handles, or inability to send or receive data across socket handles.

It is not clear what 'not duplicated accurately' means or if it even applies in this case.

Here is the test program

#! /usr/bin/env perl

use strict;
use warnings;

my $isActiveStatePerl = 1 ;  # defined(&Win32::BuildNumber);

sub pipeFromFork
{
    return open($_[0], "-|") if (!$isActiveStatePerl);
    pipe $_[0], my $child or die "cannot create pipe";

    printf STDERR "$$: pipe create parent %d child %d\n", fileno($_[0]), fileno($child);
    my $pid = fork();
    die "fork failed: $!" unless defined $pid;
    if ($pid) {         # parent
        printf STDERR "$$: fork parent close child %d\n", fileno($child);
        close $child;
    } else {            # child 
        open(STDOUT, ">&=", $child) or die "cannot clone child to STDOUT";
        printf STDERR "$$: fork child close parent %d stdout %d\n", fileno($_[0]), fileno(STDOUT);
        close $_[0];
    }
    return $pid;
}


my @transform = qw( tr [A-Za-z] [N-ZA-Mn-za-m] );  # rot13
my @inception = (
  "V xabj, Qnq. Lbh jrer qvfnccbvagrq gung V pbhyqa'g or lbh.",
  "V jnf qvfnccbvagrq gung lbh gevrq.",
);

sub snow_fortress { print STDERR "$$: 1 start\n"; print map "$_\n", @inception }

sub hotel 
{
    printf STDERR "$$: 2 start %d\n", fileno(STDIN);
    # my $pid = open STDIN, "-|";
    my $fh;
    my $pid = pipeFromFork($fh);
    print STDERR "$$: hotel: pid $pid\n";
    defined($pid)  or die "$0: fork: $!";
    if (0 == $pid) {
        snow_fortress;
        print STDERR "$$: 1 exit\n";
        exit(0);
    }
    open(STDIN, "<&", $fh)  or die "cannot clone to STDIN";
    printf STDERR "$$: 2 exec %d\n", fileno(STDIN);
    # print while <STDIN>;
    exec @transform or die "$0: exec: $!";
}

# my $pid = open my $fh, "-|";
my $pid = pipeFromFork(my $fh);
defined($pid) or die "$0: fork: $!";
print STDERR "$$: outer: pid $pid\n";

if (0 == $pid) {
    hotel;
    print STDERR "$$: 2 exit\n";
    exit(0);
}

print STDERR "$$: 3  start " . fileno($fh) . "x\n";

print while <$fh>;
print STDERR "$$: 3  end\n";
close $fh or warn "$0: close: $!";

回答1:

Option 1

-- if your input perl process is simple enough to put into a one liner

 my $cmd = "perl -e ' -- your simple perl -- ' | cmdToExecute";

 my $out;
 open my $cmdpipe "-|", $cmd;
 while (<$cmdpipe>) {
    $out .= $_;
 }

 # $out is your captured output

-- if your input perl process is complicated, put it into a file

 my $cmd = "perl compInput.pl | cmdToExecute";
 # rest as above

Option 2

- remove ActiveState perl
- install git for windows and use the perl from it.