perl - "тройник" оператора qx - PullRequest
3 голосов
/ 17 февраля 2011

Я работаю над сценарием, который в настоящее время имеет:

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

Он работает правильно, но часть some_command занимает большую часть времени сценария. И в течение этого времени ничего не появляется в stdout, потому что Perl перенаправил вывод из some_command для заполнения массива @files. Он печатается только когда some_command и Perl переходит к print @files;.

Есть ли какой-нибудь умный способ изменить этот код так, чтобы вывод some_command отображался при его выполнении? Я мог бы попробовать что-то вроде этого, используя tee(1):

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

Но я бы предпочел избегать временных файлов, если есть более простое решение.

Ответы [ 5 ]

5 голосов
/ 17 февраля 2011

Вы можете открыть дескриптор и вручную заполнить массив во время печати строк по ходу работы.

Что-то подобное может сработать,

  open my $fh, '-|', $some_command;
  while(<$fh>)
  {
    print $_;
    push @files, $_;
  }
  close $fh;
2 голосов
/ 17 февраля 2011

Вы можете пропустить оператор qx() и открыть дескриптор файла непосредственно в выходной поток процесса.Этот код функционально эквивалентен my @files = qx($some_command):

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

, но внутри цикла while вы можете делать все, что захотите, с $_:

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

Важным фактором является выходбуферное поведение $some_command.Если эта команда буферизует свои выходные данные, то ваш дескриптор $proc_fh не будет получать никаких входных данных, пока не будет доступен большой блок данных.

1 голос
/ 17 февраля 2011

Capture :: Tiny , вероятно, именно то, что вы хотите.

   use Capture::Tiny qw/ tee tee_merged /;

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

   $merged = tee_merged {
     # your code here
   };
1 голос
/ 17 февраля 2011

Вы также можете открыть свою команду в качестве файлового дескриптора и прочитать выходные данные, когда команда их производит. Как то так (взято из 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;
1 голос
/ 17 февраля 2011

Модуль File::Tee выглядит так, как будто он может делать то, что вы хотите.Там есть примеры перенаправления STDOUT при запуске system().Я не использовал его, поэтому не могу привести более конкретные примеры, но, похоже, это будет хорошим отправным пунктом для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...