4

I need to execute a command from my Perl script, which is going to take a while (1-2 hours). I want to be able to see the output of the command, so that my script can check everything went OK, but as it takes such a long time, I'd like the user to see the commands output while it runs, too.

What I've tried:

  • backticks - Can only get output when command is finished
  • system - Can only get output when command is finished
  • open - Almost perfect - but the commands output is buffered, meaning users don't see an update for a long time. Internet is full of suggestions to set $| = 1 but apparently this only affects input buffering and doesn't work
  • Piping to tee - Similar results to open - 'tee' only seems to print later
  • Re-directing output and Using Proc::Background and File::Tail - Almost perfect again, but can't think of an elegant way to stop the print loop

Would love to have a suggestion!


Edit: I've accepted Barmars answer. I believe it works because Expect.pm uses a pseudo-terminal. Just to others looking at this question in future, this is how I've implemented it:

my $process = Expect->spawn($command, @params) or die "Cannot spawn $command: $!\n";

while ($process->expect(undef))
{
  print $process->before();
}
Frederik
  • 1,458
  • 4
  • 15
  • 26
  • 2
    Have a look at http://stackoverflow.com/a/214005/1331451 – simbabque Sep 03 '12 at 09:08
  • Setting autoflush to a true value disables buffering for the currently `select`ed file handle. How is that different from what you are asking for? – TLP Sep 03 '12 at 09:19
  • TLP, as I said I tried that, and it didn't seem to work. Upon researching it, I read that autoflush only affects input buffering. – Frederik Sep 03 '12 at 09:22
  • 1
    The phrase `it doesn't work` and all its variations is next to useless without elaboration. And no, it is *output* buffering. There is no input buffering. – TLP Sep 03 '12 at 09:32
  • simbabque: I've seen that, thanks - but that solution... well, I'd rather just re-write my script in C than do that. TLP: I'm not sure what you don't understand. I'll try again: "Setting $| = 1, or fileHandle->autoflush(1); both result in the same behaviour as if they had not been set". – Frederik Sep 03 '12 at 12:00
  • It sounds like the command you are executing does not `fflush()` its output unless it detects a terminal on `stdout`. Others with similar problems might be able to force the command into interactive mode somehow. `IPC::Run` may also do what you want, but in this case it sounds like the built-in pattern matching of `Expect` is a good fit for your script. – Oktalist Sep 03 '12 at 12:30
  • 1
    @TLP, I would add more than one up to that comment if I could. – Axeman Sep 11 '12 at 13:02

1 Answers1

2

Using Expect.pm should disable output buffering in the command.

Barmar
  • 741,623
  • 53
  • 500
  • 612