The task is to pipe together two subprocesses, and we also want to be able to get both their exit codes while accumulating their output into memory.


import subprocess

params = {
    'args': ['gzip', '-dc', 'alice.txt.gz'],
    'stdout': subprocess.PIPE

with subprocess.Popen(**params) as p1:
    with subprocess.Popen(args=['tr', '[:upper:]', '[:lower:]'], stdin=p1.stdout, stdout=subprocess.PIPE) as p2:
        stdout_data, stderr_data = p2.communicate()
        print("Length of data on pipe:", len(stdout_data))

        e1 = p1.wait()
        print("Return code of p1 was:", e1)

        e2 = p2.wait()
        print("Return code of p2 was:", e2)


use IPC::Run qw(harness);
use Data::Dump qw(dump);
use v5.20.2;

my $gzip = ['gzip', '-dc', 'alice.txt.gz'];
my $tr = ['tr', '[:lower:]', '[:upper:]'];

my $buf;
my $h = harness $gzip, '|', $tr, '>', \$buf;

my @results = $h->results();

say "Length is ", length $buf;
say dump(\@results);

The comparison is slightly unfair because subprocess is a standard module, whereas IPC::Run is only available on CPAN.