How to read to and write from a pipe in perl with ActiveState Perl?
Asked Answered
P

1

0

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: $!";
Planetstruck answered 20/11, 2015 at 22:16 Comment(3)
What is the OS? I usually think of ActiveState as a perl for Windows, but I think of tr as a utility for Unix-y systems.Cuda
It's a perl script to run on multiple platforms. ActiveState is the perl provided on the Windows platfrom. tr is a perl builtin, see perlop.Planetstruck
Then it doesn't make sense to use exec to invoke a perl builtin. See perlfunc.Cuda
P
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.
Planetstruck answered 25/11, 2015 at 3:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.