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

I've a program which opens a system command which never finishes. Currently, I just:
open CMD, "/usr/local/bin/inotifywait |"; while (my $output = <CMD>) { ....... }
Rather than block for the output, I would like to start the command and spool the output to an array. Simultaneously, I would then parse the output if certain conditions exist (system load, time of day). How could I do this? Could fork be used?
my @output; while (my $line = <CMD>) { chomp $line; push @output, $line; }
Then somewhere else...
for my $out (@output) { if (condition exists) { parse output; } ..... }

Replies are listed 'Best First'.
Re: Doing two things at once, fork question.
by BrowserUk (Patriarch) on Mar 07, 2008 at 20:04 UTC

    With threads:

    #! perl -slw use strict; use threads; use threads::shared; my @output :shared; my $pid :shared; my $t = async { $pid = open CMD, qq[ perl -le"\$|++; print ~~localtime while sleep 1" |] or die $!; while( <CMD> ) { chomp; lock @output; push @output, $_; } close CMD; }; sleep 10; ## do other stuff for my $out ( do{ lock @output; @output } ) { if( $out =~ m[6] ) { print $out; } } kill 9, $pid; $t->join;

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks for the example. One question. I've read the threads perldoc. async expects an anonymous subroutine. All of my code is in a module. Is there anyway I can call async with a method? I'm not sure what the syntax would be...
        Is there anyway I can call async with a method? I'm not sure what the syntax would be...

        Yes. (Update: Corrected method syntax)

        # normal sub - no parameters. my $thread = async \&subname; # sub with args my $thread = async \&subname, $arg1, $arg2; # method - no parameters. my $thread = async \&pClass::method, $obj; # method with args my $thread = async \&Classname::method, $obj, $arg1, $arg2;

        And note that async is just a functional alias for

        my $thread = threads->create( \&sub, $arg1, $arg2 ); my $thread = threads->new( \&Classname::method, $obj, $arg1, $arg2 );

        But note. Calling objects (object methods) across threads probably won't work in most cases.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Doing two things at once, fork question.
by zentara (Cardinal) on Mar 07, 2008 at 19:45 UTC
    You can also use IPC::Open3. It's part of the faq questions.

    See "perldoc -q external command"

    There are all sorts of ways to do it, and the devil is in the details; so you need to be more specific about what type of command you need to run, and filter it's output. Some commands need a pty, and require special handling.


    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      The command is inotifywait.
Re: Doing two things at once, fork question. (IPC)
by tye (Sage) on Mar 07, 2008 at 19:25 UTC

    No, if you fork, then the two processes are separate and won't share an array. You could use threads but there is a much sexier technique that seems a much better idea for this situation: Redirect the output to a file and then read and process the output from that file when you feel like it.

    - tye        

      Thanks for the input. I assume redirecting to a file would be done using a system call. I think I will do some reading on threads.pm. I'd like to get some experience with that.