如何在Perl中实时读取外部命令的输出? [英] How can I read the output from external commands in real time in 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屋!