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

Please help. I am trying to run another program and capture the output then kill it in perl. Does anyone know a way to do it?.
The program I am trying to run will never stop, so I need to kill it somehow.
I try
@cap = `program.exe`;
this wont work because program.exe will run forever so my script will hang then crash.
I also try this but still not work
open(CMD, "program.exe |") or die "Can't run \n$!\n"; while(<LS_CMD>){ # each line of output is put into $_}
Thanks in advance.

Replies are listed 'Best First'.
Re: Run and Stop another program in perl
by BrowserUk (Patriarch) on Aug 21, 2010 at 05:09 UTC

    How will you decide when to kill it?

    If (say) you only want the first 100 lines of output you might use something like:

    my $pid = open CMD, 'program.exe |' or die $!; my @output; push @output, scalar <CMD> for 1 .. 100; kill 9, $pid; ## Do something with @output
      Thank you all for replying.
      I try it and still does not work. when perl execute line my $pid = open CMD, 'program.exe |' or die $!;. program.exe will run forever and my perl script hang. It will not get to the next line, so it can't capture the output. Also it will not get to the line kill 9, $pid.

      I try using fork too, but the same thing happen.
      Any other suggestion?.
        when perl execute line my $pid = open CMD, 'program.exe |' or die $!;. program.exe will run forever and my perl script hang.

        The only way I'm aware of that can happen is if the program produces output without any newlines.

        E.g: This (with -l so print adds newlines), returns control to the calling program immediately:

        $pid = open CMD, '-|', q[perl.exe -le"print ++$i while sleep 1"] or di +e $!;;

        But this (no newlines) won't return control to the caller until it fills and flushes the 4k buffer on STDOUT. Which given it only produces just a few characters every second, will take a long time:

        $pid = open CMD, '-|', q[perl.exe -e"print ++$i while sleep 1"] or die + $!;;

        If the program in question is buffering its output, is not adding newlines, and doesn't produce enough to fill the buffer, it will never return control to the caller.

        In that case, you're pretty much screwed unless you can recompile the program.


        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: Run and Stop another program in perl
by roboticus (Chancellor) on Aug 21, 2010 at 05:58 UTC

    fast:

    If you use fork (on an operating system that supports it well), you can set up the I/O streams and fork off the task. Then you'll have the PID (process identifier) for the forked job, and you can kill it when you decide to. Something like:

    my $child_PID = fork; if ($child_PID == 0) { # We're in the child process, so redirect I/O handles and run progr +am... close STDOUT; open STDOUT, '>', 'foobar.log' or die $!; exec 'foobar.exe', 'argument_1', 'second argument', 'etc...'; die "Couldn't find foobar.exe!"; # should never get here... } else { # We're in the parent, so wait a few seconds, and kill the child. sleep 10; kill 9, $child_PID; }

    Untested code. Testing (and any repairs required) left as an exercise for the reader...

    ...roboticus

      Why would you use forking fork instead of the built-in forking open which works everywhere? :)

        BrowserUk:

        I don't normally tie programs together in perl, thus I rarely use fork or open to connect programs together. Hence, I just used the first one I thought of. As I'm a C/C++ programmer, fork naturally came to mind. Perhaps I'll think of open next time... ;^)

        ...roboticus

      Funny that both you and BrowserUK decide to kill using SIGKILL. That's not very friendly, and not "the appropriate way" - it doesn't give the program a chance to shutdown gracefully (for instance, if the killed process would be a Perl program, sending it SIGKILL robs the program of its opportunity to run END blocks. Or to call DESTROY. Or to cleanly shut down database connections.). Send it a SIGTERM (often 15, but technically, it's architecture dependent - check $Config::Config{sig_name} if you want to cover portability issues).

        In my case, there is good reason for that. Did you notice the OPs program name: program.exe?

        On win32, it makes no difference. The following code does kill 15, but notice that it is reported by the terminatng process as sigbreak:

        Perl> $pid = open CMD, '-|', q[perl.exe -le"$SIG{TERM}=sub{print 'here +' }; $|++; print ++$i while sleep 1"] or die $!;; Perl> print scalar <CMD> for 1 .. 10;; 1 2 3 4 5 6 7 8 9 10 Perl> kill 15, $pid;; Terminating on signal SIGBREAK(21)

        The pseudo signals perl provides on win32 are useful, but limited. And bear very little resemblance to POSIX signal handling.


        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: Run and Stop another program in perl
by eyepopslikeamosquito (Archbishop) on Aug 21, 2010 at 13:01 UTC

    Given you appear to be running on Windows, another option is to use the Win32::Job module. An example of doing that can be found at:

Re: Run and Stop another program in perl
by dwhite20899 (Friar) on Aug 24, 2010 at 00:45 UTC
    My suggestion is to read about the alarm() funtion, although it's different across many Windows platforms.

    Effectively, you can set a timer, run program.exe for the amount of time you choose, then the exe will be killed, and your script will continue.