如何在Perl中实时读取外部命令的输出? [英] How can I read the output from external commands in real time in Perl?

查看:53
本文介绍了如何在Perl中实时读取外部命令的输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a few bash scripts I run, but they can take several hours to finish, during which time they spew out download speeds, ETAs and similar information. I need to capture this information in perl, but I am running into a problem, I cannot read the output line by line(unless I'm missing something).

有什么帮助吗?

为更好地解释这一点,我正在彼此并排运行多个bash脚本,我希望将gtk与perl结合使用以产生方便的进度条.目前,我要运行的每个bash脚本都运行2个线程,一个用于更新图形信息的主线程.看起来像这样(尽我所能减少):

to explain this a little better I'm running several bash scripts along side each other, I wish to use gtk with perl to produce handy progress bars. At present I'm running 2 threads for every bash script I wish to run, one master thread for updating the graphical information. It looks something like this(cut down as much as I possibly can):

  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.
  }

推荐答案

代替线程和``,请使用:

Instead of threads, and ``, use:

 open my $fh, '-|', 'some_program --with-options';

通过这种方式打开几个文件句柄(需要运行许多程序),然后使用 IO :: Select 从其中轮询数据.

In this way open several filehandles (as many as many programs you need to run) and then use IO::Select to poll data from them.

简单的例子.

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

Let's assume I have shell script that looks like this:

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

其输出可能如下所示:


=> ./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 :

Now, let's write a 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;
    }
}

如您所见,没有分叉,没有线程.这就是它的工作方式:

As you can see there are no forks, no threads. And this is how it works:


=> 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

这篇关于如何在Perl中实时读取外部命令的输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆