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

Hello. Running Activestate 5.16 on Win32. I have a program that will generate output continually, I need to only capture output to a file for a little while. I can't seem the exit the while loop tho' any ideas? I tried until(), last()..... Must I put a space in $arg0 ? e.g. $arg0 = " \"arb..\""; ----------------------------- #!perl $program = "c:\\progdir\\bin\\proggie.exe"; $dstfile = "d:\\scripts\\log\\archive\\proggie.log"; $arg0 = "\"Blah.Blech.>\""; $timeout = 60; $starttime = time; open( PRG, "$program $arg0 |") || die "Couldn't open PRG: $!\n"; open (LF, ">$finaldest"); while (<PRG>) { print LF "$_"; $difftime = time - $starttime; last if ($difftime > $timeout); } close (LF); close (RVRD);
  • Comment on Exiting from capturing output in a while?

Replies are listed 'Best First'.
Re: Exiting from capturing output in a while?
by BlaisePascal (Monk) on Aug 08, 2000 at 05:06 UTC
    I can't see anything obviously wrong with his code (except not checking the result of opening the log file and the last close is incorrect), but here's his code so others can look at it:
    #!perl $program = "c:\\progdir\\bin\\proggie.exe"; $dstfile = "d:\\scripts\\log\\archive\\proggie.log"; $arg0 = "\"Blah.Blech.>\""; $timeout = 60; $starttime = time; open( PRG, "$program $arg0 |") || die "Couldn't open PRG: $!\n"; open (LF, ">$finaldest"); while (<PRG>) { print LF "$_"; $difftime = time - $starttime; last if ($difftime > $timeout); } close (LF); close (RVRD);
    Tip to the anonymous monk: If you include your code in <CODE> tags, it will get formatted correctly.
Re: Exiting from capturing output in a while?
by Adam (Vicar) on Aug 08, 2000 at 05:09 UTC
    Your code as best I can make it out: (please use code tags in the future)
    #!perl $program = "c:\\progdir\\bin\\proggie.exe"; $dstfile = "d:\\scripts\\log\\archive\\proggie.log"; $arg0 = "\"Blah.Blech.>\""; $timeout = 60; $starttime = time; open( PRG, "$program $arg0 |") || die "Couldn't open PRG: $!\n"; open (LF, ">$finaldest"); while (<PRG>) { print LF "$_"; $difftime = time - $starttime; last if ($difftime > $timeout); } close (LF); close (PRG);
    My untested suggestion:
    #!perl use strict; # ALWAYS! (Why? Helps catch typos before run time... among + other things) $|=1; # This disables buffering. JCWren's Suggestion. my $program = 'c:\progdir\bin\proggie.exe'; my $dstfile = 'd:\scripts\log\archive\proggie.log'; my $arg0 = '"Blah.Blech.>"'; my $timeout = 60; open( PRG, "$program $arg0 |") or die "Couldn't open '$program $arg0', + $!"; open(LF, ">$finaldest") or die $!; my $inloop = 0; my $endtime = time + $timeout; # Only do the math once. while( <PRG> and $endtime >= time ) # '>=' or '>', your choice. { if( not $inloop ) { # This will get run the first time, but not after. # As per JCWren's Suggestion. print STDERR "Inside Loop\n"; $inloop = 1; } chomp; print LF $_, "\n"; } close(LF) or die $!; close(PRG) or die $!;
    Of course most of this is clean up, I can't see anything really wrong with your code. I don't usually use last since I don't always see it when looking for exits from a loop. Of course, last ought to work, so I tried a simple cmd liner:
    C:\>perl -we "$i=0;$stop=time +2;while(1){print $i++, qq!\n!; last if +time > $stop}"
    Which ran for roughly two seconds, no problem.
      A couple of basic debugging tests need to be applied here:
      1. Have you proven that you're getting to the 2nd open statement?
      2. Have you proven you're actually spending time in the loop?

      It seems to me that it the program 'proggie.exe' never exits, then if open() uses a system() call internally, and not a fork(), it's waiting for the program to finish before the output will be passed back to the calling process (i.e. your script).

      In a *nix land, this might work, I don't know for sure. But in a Windows environment, I think you're going to have problems.

      I would recommend turning off buffering ($| = 1) and putting some judicious print statements to make sure you're getting as far as you think you are.

      --Chris

      e-mail jcwren
Re: Exiting from capturing output in a while?
by Anonymous Monk on Aug 09, 2000 at 03:07 UTC
    Hello. This is what I've done, it runs fine except the only problem is that it complains about not being able to write to the ">" destination (new_logfile.txt).
    use Win32::Process; $program = "c:\\perl\\scripts\\tail.exe"; $arg0 = " > c:\\perl\scripts\\logfile.txt > c:\\perl\\scripts\\new_log +file.txt"; Win32::Process::Create($ProcessObj, "$program", "$arg0", 0, NORMAL_PRI +ORITY_CLASS, ".")|| die ErrorReport(); until ($endit < time) { next; } $pid = $ProcessObj->GetProcessID(); Win32::Process::KillProcess($pid, $exitcode);
RE: Exiting from capturing output in a while?
by Fastolfe (Vicar) on Aug 09, 2000 at 00:28 UTC
    Your method is probably quite sufficient and satisfactory, but I'm trying to get into the habit of offering alternatives. I don't think this is particularly viable for Windows, since I don't believe Perl supports the alarm() call, and I don't know how signals are supported, but something like this might also accomplish your ends:
    $SIG{ALRM} = \&Done; alarm $timeout; # Set your timeout here, in secs while (<INPUT>) { print OUTPUT $_; # Do whatever } alarm 0; # So as not to trip ALRM after we're done +with INPUT close(OUTPUT); # Likewise, in case we got an EOF in INPUT + before $timeout close(INPUT); sub Done { close(OUTPUT); # Do your cleanup and optionally exit close(INPUT); exit 0; }
    Correct me if I'm wrong, but once Done returns (assuming you let it), the while() loop can't continue (since the INPUT file handle is closed), so program execution could proceed normally at that point. If that's the case, you might want to localize $SIG{ALRM}. You can also use a closure instead of a sub reference for the value of $SIG{ALRM}.