7stud has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I'm wondering if you can kill a process that you started with a pipe, e.g.:

open $PIPE_READER, "some_command |";

The IPC docs seem to suggest that you can:

You might notice that you could use backticks for much the same effect as opening a pipe for reading:

<snip code>

While this is true on the surface, it's much more efficient to process the file one line or record at a time because then you don't have to read the whole thing into memory at once. It also gives you finer control of the whole process, letting you to kill off the child process early if you'd like.

section: Using open() for IPC

Replies are listed 'Best First'.
Re: pipes: killing the child?
by ikegami (Patriarch) on Jan 21, 2010 at 05:52 UTC
    That form of open returns the child's pid, which you can pass to kill.
    kill TERM => $pid;

    Correction! It's much simpler than that. Closing the handle will close the pipe, which will result in the child killing itself (SIGPIPE) the next time it attempts to write to it.

    Since closing the handle also waits for the child to end, kill can still come in useful if the child only writes to the handle sporadically.

    my $pid = open(my $fr_chld, '-|', $^X, -le => '$|=1; { print ++$i; sleep 1; redo; }' ); print scalar <$fr_chld> for 1..4; #kill TERM => $pid; close($fr_chld); if ($? & 127) { require Config; my @sig_names = split ' ', $Config::Config{sig_name}; print("Child died from SIG$sig_names[$? & 127]\n"); } elsif ($? >> 8) { print("Child exited with error ", ($? >> 8), "\n"); } else { print("Child exited successfully\n"); }
    1 2 3 4 Child died from SIGPIPE

    That brings up another advantage of open '-|' over backticks: You can use the multi-argument form to avoid invoking the shell.

    Update: Added correction.

      That form of open returns the child's pid...

      Yikes! I did not know that.

      Correction! It's much simpler than that. Closing the handle will close the pipe, which will result in the child killing itself (SIGPIPE) the next time it attempts to write to it.

      I knew that but I didn't remember it.

      my $pid = open(my $fr_chld, '-|', $^X, -le => '$|=1; { print ++$i; sleep 1; redo; }' );

      I spent an hour trying to decipher that line, but I don't get it. As far as I can tell, '-|' forks the program, but then whey do you have to list $^X?

        As far as I can tell, that wants to be an example child process to demonstrate what will happen when you close a filehandle associated with a long-running, sporadically outputting process (without STDOUT buffering). As if your child were this:
        perl -le '$|=1; { print ++$i; sleep 1; redo; }'
        In the original post's terms this is similar to: open( my $fr_chld, "perl -le '...' |" )
        It's like
        system($^X, -le => '$|=1; { print ++$i; sleep 1; redo; }')

        but it doesn't wait for the child to end before continuing, and the child's STDOUT ends up in $fr_chld instead of being sent to the parent's STDOUT.

        As for the command itself, my demo program runs Perl ($^X) to execute an infinite loop ({ ...; redo; }) which outputs a number every second (print ++$i; sleep 1;).

      The IPC::Open docs say:

      Since Perl 5.8.0, you can also use the list form of open for pipes : the syntax
      open KID_PS, "-|", "ps", "aux" or die $!;

      forks the ps(1) command...

      I don't understand the terminology "forks the ps(1) command". As far as I know, a fork() copies the current program and runs it in another process. So how can you "fork() a command"? Doesn't fork() always copy the current program rather than run a specified command? Do the IPC docs really mean a fork(), which copies the current program and runs it in a another process, plus an exec() in the child which replaces the current program with the command?

        Yes, "forks the ps(1) command" is short for "forks and execs the ps(1) command in the child".
        Yup, the docs do really mean what they say :)