Reputation: 167
I have a Perl program(this is the PARENT) which needs variables from another Perl prog(CHILD). I want to realize that with the pipe mechanism of Linux. After unsuccessfull search in net (none of the numerous examples fit this basic theme -- I think the concept is quite understandable for a nonexpert, but I cannot implement a running example). The two appended progs show my understanding of piping, which is probably totally wrong, but I want to learn it. For clarity:
Prog PARENT is running
needs 2 variables from Prog CHILD
PARENT calls CHILD (open CHILD ... ?)
CHILD is running and can deliver the 2 variables
CHILD opens PARENT, write/print the variables to PARENT
CHILD closes PARENT
CHILD exit
PARENT can now read from CHILD
The PARENT Program (Caller and Receiver)
#!/usr/bin/env perl
use strict;
use warnings;
# file-name: mwe-ipc.pl
# this prog. is the PARENT
# Calls a CHILD by its prog.name
print "$0\n"; # show your progname
my $pid = open(CHILD, "mwe-ipc-child.pl |") or die "Couldn't fork: $!\n";
my @arr_receiver;
while (<CHILD>){
# PARENT needs two variables from CHILD
# how to get var1 and var2?
@arr_receiver = $_;
}
close(CHILD);
print "arr_receiver[$_] = $arr_receiver[$_]\n" for (0..$#arr_receiver);
The CHILD Program (will be called and answers)
#!/usr/bin/env perl
use strict;
use warnings;
# file-name: mwe-ipc-child.pl
# this prog. is the CHILD
# Called from a PARENT
print "$0\n";;
my $pid = open(PARENT, "| mwe-ipc.pl") or die "Couldn't fork: $!\n";
my $var1 = "a"; #"|l |p{2.7cm} |p{2cm}";
my $var2 = "b"; #"\textbf{G}& \textbf{Substantiv}& \textbf{Modus} \\";
while (<PARENT>){
# PARENT needs two variables from CHILD
# how to put var1 and var2?
print PARENT $var1, $var2;
}
close(PARENT);
exit(0);
Call to PARENT Prog outputs progname, then endless loop. Ultimately needless call from cmdline of CHILD delivers own and PARENTS' progname. Can someone please help?
Upvotes: 2
Views: 108
Reputation: 167
Many, many Thanks for your answer. Your solution works as it is. But for those who are similar interested as me I want to show following adaption of your source which should fit exactly the original question. Interchange variables from a child to parent. Important additional knowledge is here
1) do{local... in: https://www.perlmonks.org/?node_id=287647
2) no suffer from buffer in: Why doesn't my parent process see the child's output until it exits?
The parent:
#!/usr/bin/env perl
use strict;
use warnings;
# file-name: mwe-ipc.pl
# this prog. is the PARENT
# Calls a CHILD by its prog.name
print "$0\n";
use utf8;
use open ':std', ':encoding(UTF-8)';
open(my $CHILD, "-|", "mwe-ipc-child.pl") or die("Can't execute child: $!\n");
# do { local $/; <$CHILD> }; this idiom is a consise way to slurp the entire
# contents of a file into a scalar without using a loop
# $/ is the inut record separator(irs). In following manner the same as
# local $/ = undef. This eliminates the irs to nothing, which leads to a slurp
# instead of reacting upon \n, the default value, the new line sign.
# Local restricts that behaviour to the block {}.
my $response = do { local $/; <$CHILD> };
close($CHILD);
#... do something with response...
print "response from child is : $response \n";
my @arr_response = split /\n/, $response;
print "arr_response[$_] = $arr_response[$_]\n" for (0..$#arr_response);
The Child:
#!/usr/bin/env perl
use strict;
use warnings;
# file-name: mwe-ipc-child.pl
# this prog. is the CHILD
# Called from a PARENT
#print "$0\n"; # uncommented this print goes to the PARENT too.
use open ':std', ':encoding(UTF-8)';
my $var1 = "|l |p{2.7cm} |p{2cm}";
my $var2 = "\\textbf{G}& \\textbf{Substantiv}& \\textbf{Modus} \\\\";
my @response;
print ($var1,"\n", $var2,"\n");
The call of "mwe-ipc.pl" leads to
/home/hj/latex/mwes/ipc/mwe-ipc.pl
response from child is : |l |p{2.7cm} |p{2cm}
\textbf{G}& \textbf{Substantiv}& \textbf{Modus} \\
and
arr_response[0] = |l |p{2.7cm} |p{2cm}
arr_response[1] = \textbf{G}& \textbf{Substantiv}& \textbf{Modus} \\
So, exactly what I wanted, thanks @ikegami
Upvotes: 0
Reputation: 385857
Problem #1: Fundamentals
Having the child execute the parent makes no sense. The output to be captured by the parent should be sent to STDOUT.
The starting skeletons would look as follows:
Parent:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use open ':std', ':encoding(UTF-8)';
open(my $CHILD, "-|", "mwe-ipc-child.pl")
or die("Can't execute child: $!\n");
my $response = do { local $/; <$CHILD> };
close($CHILD);
... do something with response...
Child:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use open ':std', ':encoding(UTF-8)';
my $response = ...;
print($repsonse);
Problem #2: Protocol
You need some kind of way of telling where one value ends and the other starts.
If the values will never contain a line feed, you could separate them using a line feed.
Child:
print("$var1\n$var2\n");
Parent:
chomp( my $var1 = <$CHILD> );
chomp( my $var2 = <$CHILD> );
Otherwise, a nice extensible method would be to use JSON.
Child:
use Cpanel::JSON::XS qw( encode_json );
my $data = { var1 => $var1, var2 => $var2 };
my $json = encode_json($data);
binmode(STDOUT);
print($json);
Parent:
use Cpanel::JSON::XS qw( decode_json );
open(my $CHILD, "-|:raw", "mwe-ipc-child.pl") or ...;
my $json = do { local $/; <$CHILD> };
close($CHILD);
my $data = decode_json($json);
my $var1 = $data->{var1};
my $var2 = $data->{var2};
Upvotes: 4