如何在Perl中实时读取外部命令的输出?

scr*_*gar 5 bash perl stdin

我运行了一些bash脚本,但它们可能需要几个小时才能完成,在此期间它们会发出下载速度,ETA和类似信息.我需要在perl中捕获这些信息,但是我遇到了一个问题,我无法逐行读取输出(除非我遗漏了一些东西).

任何帮助解决这个问题?

编辑:更好地解释这个我正在运行几个bash脚本,我希望使用gtk与perl生成方便的进度条.目前我为每个我希望运行的bash脚本运行2个线程,一个用于更新图形信息的主线程.它看起来像这样(尽可能减少):

  my $command1 = threads->create(\&runCmd, './bash1', \@out1);
  my $controll1 = threads->create(\&monitor, $command1, \@out1);
  my $command1 = threads->create(\&runCmd, 'bash2', \@out2);
  my $controll2 = threads->create(\&monitor, $command2, \@out2);

  sub runCmd{
     my $cmd = shift;
     my @bso = shift;
     @bso = `$cmd`
  }
  sub monitor{
     my $thrd = shift;
     my @bso = shift;
     my $line;
     while($thrd->is_running()){
       while($line = shift(@bso)){
         ## I check the line and do things with it here
       }
       ## update anything the script doesn't tell me here.
       sleep 1;# don't cripple the system polling data.
     }
     ## thread quit, so we remove the status bar and check if another script is in the queue, I'm omitting this here.
  }
Run Code Online (Sandbox Code Playgroud)

小智 8

而不是线程和``,使用:

 open my $fh, '-|', 'some_program --with-options';
Run Code Online (Sandbox Code Playgroud)

以这种方式打开几个文件句柄(您需要运行多个程序),然后使用IO::Select它们来轮询数据.

简单的例子.

我们假设我的shell脚本如下所示:

=> cat test.sh
#!/bin/bash
for i in $( seq 1 5 )
do
    sleep 1
    echo "from $$ : $( date )"
done
Run Code Online (Sandbox Code Playgroud)

它的输出可能如下所示:

=> ./test.sh
from 26513 : Fri Aug  7 08:48:06 CEST 2009
from 26513 : Fri Aug  7 08:48:07 CEST 2009
from 26513 : Fri Aug  7 08:48:08 CEST 2009
from 26513 : Fri Aug  7 08:48:09 CEST 2009
from 26513 : Fri Aug  7 08:48:10 CEST 2009

现在,让我们写一个multi-test.pl:

#!/usr/bin/perl -w
use strict;
use IO::Select;

my $s = IO::Select->new();

for (1..2) {
    open my $fh, '-|', './test.sh';
    $s->add($fh);
}

while (my @readers = $s->can_read()) {
    for my $fh (@readers) {
        if (eof $fh) {
            $s->remove($fh);
            next;
        }
        my $l = <$fh>;
        print $l;
    }
}
Run Code Online (Sandbox Code Playgroud)

如你所见,没有叉子,没有线程.这就是它的工作原理:

=> time ./multi-test.pl
from 28596 : Fri Aug  7 09:05:54 CEST 2009
from 28599 : Fri Aug  7 09:05:54 CEST 2009
from 28596 : Fri Aug  7 09:05:55 CEST 2009
from 28599 : Fri Aug  7 09:05:55 CEST 2009
from 28596 : Fri Aug  7 09:05:56 CEST 2009
from 28599 : Fri Aug  7 09:05:56 CEST 2009
from 28596 : Fri Aug  7 09:05:57 CEST 2009
from 28599 : Fri Aug  7 09:05:57 CEST 2009
from 28596 : Fri Aug  7 09:05:58 CEST 2009
from 28599 : Fri Aug  7 09:05:58 CEST 2009

real    0m5.128s
user    0m0.060s
sys     0m0.076s