开发者

perl - "tee" the qx operator

I'm working on a script that currently has:

my @files = `$some_command`;
print @files;
chomp @files;
foreach my $file (@files)
{
    process($file);
}

It works correctly, but the some_command part takes the majority of the script's time. And during that time, nothing appears on stdout, because Perl has redirected output from some_command to populate the @files array. It only gets printed when some_command is done and Perl moves on to print @files;.

Is there some clever way to change this code so that the output of some_command appears as it is executing? I could maybe try something like this using tee(1):

my $tmpfile = File::Temp->new();
system("$some_command | tee " . $tmpfile->filename);
my @files;
{ local $/ = undef; @files = split /\s/, <$tmpfile>; }

But I'd rather avoid the temporary file stuff if t开发者_运维技巧here's a simpler solution.


You could open the handle and manually populate the array yourself while printing the lines as you go.

Something like this would probably work,

  open my $fh, '-|', $some_command;
  while(<$fh>)
  {
    print $_;
    push @files, $_;
  }
  close $fh;


You could skip the qx() operator and open a filehandle to the process's output stream directly. This code in functionally equivalent to my @files = qx($some_command):

 my @files = ();
 open my $proc_fh, "$some_command |";
 while (<$proc_fh>) {
     push @files, $_;
 }
 close $proc_fh;

but inside the while loop you can do whatever you want with $_:

 while (<$proc_fh>) {
     print "INPUT: $_\n";
     push @files, $_;
 }

An important consideration is the output buffering behavior of $some_command. If that command buffers its output, then your $proc_fh handle will not receive any input until a large block of data is available.


The File::Tee module looks like it could do what you want. There are examples there of redirecting STDOUT when running system(). I haven't used it, so I can't give more concrete examples, but it looks like this would be a good jumping-off point for you.


You could also open your command as a file descriptor and read the output as the command is producing it. Something like this (taken from http://www.netadmintools.com/art269.html):

#!/usr/bin/perl
open (PINGTEST, "/bin/ping  -c 5 netadmintools.com |");
$i=1;
while (<PINGTEST>){
print "Line # ".$i." ".$_;
$i++;
}
print "All done!\n";
close PINGTEST;


Capture::Tiny is probably exactly what you want.

   use Capture::Tiny qw/ tee tee_merged /;

   ($stdout, $stderr) = tee {
     # your code here
   };

   $merged = tee_merged {
     # your code here
   };
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜