Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: process string with shell command (pipe)

Tags:

pipe

perl

Assume a pipeline with three programs:

start | middle | end

If start and end are now part of one perl script, how can I pipe data through a shell command in the perl script, in order to pass through middle?

I tried the following (apologies for lack of strict mode, it was supposed to be a simple proof of concept):

#!/usr/bin/perl -n

# Output of "start" stage
$start = "a b c d\n";

# This shell command is "middle"
open (PR, "| sed -E 's/a/-/g' |") or die 'Failed to start sed';

# Pipe data from "start" into "middle"
print PR $start;

# Read data from "middle" into "end"
$end = "";
while (<PR>) {
    $end .= $_;
}

close PR;

# Apply "end" and print output
$end =~ s/b/+/g;

print $end;

Expected output:

- + c d

Actual output:

none, until I hit ENTER, then I get - b c d. The middle command is receiving data from start and processing it, but the output is going to STDOUT instead of end. Also, the attempt to read from middle seems to be reading from STDIN instead (hence the relevance of hitting ENTER).

I'm aware that this could all easily be done in one line of perl (or sed); my problem is how to do piping in perl, not how to replace chars in a string.

like image 234
Mark K Cowan Avatar asked Sep 15 '25 10:09

Mark K Cowan


1 Answers

You can use IPC::Open2 for this.

This code creates two file handles: $to_sed, which you can print to to send input to the program, and $from_sed which you can readline (or <$from_sed>) from to read the program's output.

use IPC::Open2;

my $pid = open2(my ($from_sed, $to_sed), "sed -E 's/a/-/g'");

Most often it is simplest to involve the shell, but there is an alternative call that allows you to bypass the shell and instead run a program and populate its argv directly. It is described in the linked documentation.

like image 174
Borodin Avatar answered Sep 17 '25 07:09

Borodin