如何实时读取外部程序的STDOUT?

时间:2013-01-23 09:00:07

标签: perl process external stdout

让我详细说明。

说我有perl程序

(这是从perl无耻地复制和编辑的 http://perldoc.perl.org/perlfaq8.html#How-can-I-open-a-pipe-both-to-and-from-a-command%3f

 use IPC::Open3;

 use Symbol qw(gensym);   

 use IO::File;
 local *CATCHOUT = IO::File->new_tmpfile;
 local *CATCHERR = IO::File->new_tmpfile;

 my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "ping -t localhost");

 #waitpid($pid, 0);   

seek $_, 0, 0 for \*CATCHOUT, \*CATCHERR;

 while( <CATCHOUT> ) {

print $_;
}

但是上面这个程序的问题是它会在这种情况下属于程序ping.exe的STDOUT的readtoEnd(),并允许它一次性读取。

但我想要做的是读取STDOUT,因为它被写到STDOUT。

如果我删除waitforpid(),程序会立即退出,所以这也无济于事。

这可能吗?如果是这样,请指点我正确的方向。

更新: Drats !!!!我错过了|符号...这对于将输出管道输出到perl脚本中是必不可少的!

2 个答案:

答案 0 :(得分:3)

use IPC::Open3 qw( open3 );

open(local *CHILD_STDIN, '<', '/dev/null') or die $!;

my $pid = open3(
   '<&CHILD_STDIN',
   my $child stdout,
   '>&STDERR',
   'ping', '-t', 'localhost',
);

while (<$child_stdout>) {
   chomp;
   print("Got: <<<$_>>>\n");
}

waitpid($pid, 0);

但这可以写成

open(my $ping_fh, '-|', 'ping', '-t', 'localhost') or die $!;

while (<$ping_fh>) {
   chomp;
   print("Got: <<<$_>>>\n");
}

close($ping_fh);

这只是显示了正确的用法。如果这些不起作用,则是一个无关的问题:ping在没有连接到终端时缓冲它的IO。你可以使用伪tty欺骗它。

答案 1 :(得分:2)

perl的优点之一(或弱点)是,有多种方法可以做事。这有效:

perl -e 'open(F,"ping localhost|"); while(<F>) { s/ms/Milliseconds/; print $_; }'

只需输入s / ms / Milliseconds /即可显示正在读取和更改的数据 不确定Open3

到底有什么问题