Create a pipeline just like your shell would.
Here's our scary string:
my $str = "foo * ~ bar \0 baz *";
We'll build our pipeline backwards, so first we gather the output from the Java program:
my $pid1 = open my $fh1, "-|";
die "$0: fork: $!" unless defined $pid1;
if ($pid1) {
# grab output from Java program
while (<$fh1>) {
chomp;
my @c = unpack "C*" => $_;
print "$_\n => @c\n";
}
}
Note the special "-|"
argument to Perl's open
operator.
If you open a pipe on the command '-'
, i.e., either '|-'
or '-|'
with 2-arguments (or 1-argument) form of open()
, then there is an implicit fork
done, and the return value of open
is the pid of the child within the parent process, and 0
within the child process … The filehandle behaves normally for the parent, but i/o to that filehandle is piped from/to the STDOUT
/STDIN
of the child process.
The unpack
is there to peek into the contents of the data read from the pipe.
In your program, you'll want to run the Java program, but the code below uses a reasonable facsimile:
else {
my $pid2 = open my $fh2, "-|";
die "$0: fork: $!" unless defined $pid2;
if ($pid2) {
$| = 1;
open STDIN, "<&=" . fileno($fh2)
or die "$0: dup: $!";
# exec "java", "-jar", "java_program.jar";
# simulate Java program
exec "perl", "-pe", q(
BEGIN { $" = "][" }
my @a = split " ", scalar reverse $_;
$_ = "[@a]\n";
);
die "$0: exec failed";
}
Finally, the humble grandchild simply prints the scary string (which arrives on the standard input of the Java program) and exits. Setting $|
to a true value flushes the currently selected filehandle and puts it in unbuffered mode.
else {
print $str;
$| = 1;
exit 0;
}
}
Its output:
$ ./try
[*][zab][][rab][~][*][oof]
=> 91 42 93 91 122 97 98 93 91 0 93 91 114 97 98 93 91 126 93 91 42 93 91 111 111 102 93
Note that the NUL survives the trip.