There is pipe. Pipe is lower level than shell pipes so is more flexible. It is possible to set up arbitrary networks of processes with pipe, fork, and select. The complexity of such things prevents their use, but that is not a limit of Perl.
It is pretty easy to set up a coprocess which you can print stuff to, and read back the result. Skeletal version:
my ($pin,$pout,$cin,$cout,%kid);
{
pipe $pin, $cout;
pipe $cin, $pout;
my $cpid = fork;
die $! unless defined $cpid;
$kid{$cpid} = 1, last if $cpid; # parent
close $pin or die $!; # in child to end of block
close $pout or die $!;
while (<$cin>) {
# do filter-like stuff to $_
print $cout $_;
}
exit 0;
}
# parent
close $cin or die $!;
close $cout or die $!;
# print to $pout and read from $pin, maybe in a select loop
# depends on expected behavior of the child.
delete $kid{wait()} while %kid;
The complication of that could be wrapped in a module, and probably has been.