Update: See IPC-Run or Proc-SafeExec for much more robust ways to deal with this issue.

This was inspired by FileHandle->close() is not closing everything, where children in a piped open apparently won't terminate. This snippet opens a filehandle to a pipeline of system commands, and sends pids of child processes to the parent process (for possible later termination assuming the children don't fork other children which won't terminate, etc. Or whatever purpose you can think up...). This was mainly a learning exercise, so any pointers to more developed CPAN modules are welcome (and at the time of this writing, CPAN is down). This method of forking has the additional benefit of calling exec with a list of arguments, bypassing the shell, so there's no need to quote args or avoid metacharacters in the arguments.

It may take a bit of tweaking to make this more robust, but I think its a decent starting point. This seems to work, but I'm open to comments.
Update: one possible improvement might be to use flock so that only one child at a time can write the pid info to the parent (not sure if you can flock a pipe handle, or if it would do any good).
Update: Combined 2 subroutines into one.
Update: I've found you can't depend on the order in which the pids are read, so I've added a counter to sort by.

#!/usr/bin/perl sub pipeline { pipe my ($read, $write); my $pid = open(my $fh, "-|"); die "Couldn't fork: $!" unless defined $pid; if ($pid) { close $write; chomp(my @pids = map { $_->[1] } sort { $b->[0] <=> $a->[0] } map +{ [ split /_/ ] } <$read>); close $read; return $fh, @pids; } close $read; exit unless @_; my $cnt; while (my $command = pop) { $cnt++; my $pid = @_ ? open(STDIN, "-|") : -1; die "Couldn't fork: $!" unless defined $pid; next unless $pid; print $write "${cnt}_$$\n"; close $write; exec @$command; die "Couldn't exec @$command"; } } # Silly example, but you get the idea # essentially the same as: # open($fh, "ls -1 | sed -e s/t/a/g |") my ($fh, @pids) = pipeline( [qw(ls -1)], [qw(sed -e s/t/a/g)], ); while (<$fh>) { print "$.:$_"; } close $fh; print "Pids: @pids\n";

In reply to Collecting pids from children, their children, etc. (aka: pipeline of system(@list) calls) by runrig

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.