Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

get command output line by line before it has returned

Status
Not open for further replies.

hungryhungryhippo

Programmer
Oct 23, 2007
26
DE
Hi everyone,
I'm trying to get the output of a command - preferably line by line - before it has returned.
Say you have some command outputting stuff over a length of time. like this:
Code:
#!/usr/bin/perl

foreach (1..10) {
  print 'This is cycle '.$_."\n";
  sleep(1);
}

Now you have a program that invokes such a command and you don't want it to wait for the command to finish but to get every line the command produces as soon as it would be written to the terminal. how do i do that?
it doesn't have to be non-blocking, i just need every line of output immediately. I'm using perl 5.8.8 on Debian Etch. Thanks and best Regards,

Michael
 
Code:
#!/usr/bin/perl
[b]$|=1; #turn off buffering[/b]
foreach (1..10) {
  print "This is cycle $_.\n";
  sleep(1);
}

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
this is definately interesting, but not exactly what i'm looking for. it does work fine when i'm dealing with my own perl scripts, but the code snippet above was just an example for the sort of output i mean. but i can't rely on being able to change the invoked command to disable buffering.

i have a program that wants to read the output of an arbitrary command...like this:
Code:
#!/usr/bin/perl

open (CMD,"make-kpkg --initrd kernel_image |");
while (<CMD>) {
  print;
}
close CMD;

it rather seldomly runs a script i wrote myself and i could change in the manner you described above. but thanks anyways, because i didn't know about that var and i'm sure it'll be useful to me :) any more ideas?

greetings,
michael
 
It's the only way I know of. Any other solution will probably not be a perl solution, but maybe someone else will have a suggestion.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Hi,
works like a charm! thanks a lot!!
It took me a couple of minutes to get the hang of it, but the modules documentation is quite helpful. I'll still have to play around with the timing issue a bit, but if i don't find a good solution i can live with getting the output accumulated over one second. i'll disqualify polling - the greedy drain on the cpu - because it's just impolite to hog all resources... :)
In case someone is also interested in this topic, here's some demo code:
Code:
#!/usr/bin/perl

use Expect;
use Tk;

my $mw = new MainWindow();
my $button = $mw->Button(-text=>"Go",-command=>sub { &execute(); })->pack();
my $text = $mw->Text()->pack();

MainLoop();

sub execute {
  my $exp = new Expect();     # create expect object
  my @return;
  $exp->raw_pty(1);           # set pty to raw mode
  $exp->spawn('perl', 'test.pl'); # your command with args
  
  do {
    @return = $exp->expect(1); # gather output for 1 sec and return
    $text->insert("end",$exp->clear_accum()); # insert output into textbox
    $text->idletasks;          # update textbox
  } while (substr($return[1],0,1) != '3');
     # do so until the command exits
}

not too beautyful, but this illustrates what i needed this for. imagine you don't see the output of the invoked programs, because you just double-click the .pl file and you don't get a temrinal window but only the tk interface.
test.pl is this one i posted before:

Code:
#!/usr/bin/perl

foreach (1..10) {
  print 'This is cycle '.$_."\n";
  sleep(1);
}

i hope this is also a bit helpful to other people, thanks again very much for the tip with expect.pm!

greetings

michael
 
Hi again,
to get finer time resolution you can
Code:
use Time::HiRes 'nanosleep';
, $obj->expect(0) to poll once and nanosleep() for pretty short periods of time in the loop that gathers the output.

cheers
 
You could pipe the output to logfiles and just tail them, might be a bit of a headwreck in terms of housekeeping, but it is another possibility.

Paul
------------------------------------
Spend an hour a week on CPAN, helps cure all known programming ailments ;-)
 
hi,
i tried that, but it didn't work. either because the piping locks the file, or because of buffering. i csn't modify the executed commands to disable buffering, so it doesn't really matter for what reason it didn't work. but thanks for the tip anyway :)
apart from that i still needed a way to run the command asynchronously so that perl won't wait for it to return. (i know, i can fork the call, expect does that too...).
the expect thingie also has the advantage that i can use interactive commands.
again, thanks anyway :) every idea is welcome!

cheers,
michael
 
Yeah.. if you can't open them and have perl read them one line at a time |'ing them to file isn't going to be any better.



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those who say it cannot be done are usually interrupted by someone else doing it; Give the wrong symptoms, get the wrong solutions;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top