2013-06-18 41 views
1

我想執行外部命令rtmpdump並單獨讀取它的STDOUTSTDERR,但不要等到這樣的命令結束,而是讀取它的部分輸出, 。無需等待讀取STDOUT和STDERR的外部命令

什麼是安全的方式做到這一點在Perl?


這是一個代碼,我有「每行」的基礎工作:

#!/usr/bin/perl 

use warnings; 
use strict; 
use Symbol; 
use IPC::Open3; 
use IO::Select; 

sub execute { 
    my($cmd) = @_; 
    print "[COMMAND]: $cmd\n"; 
    my $pid = open3(my $in, my $out, my $err = gensym(), $cmd); 
    print "[PID]: $pid\n"; 
    my $sel = new IO::Select; 
    $sel->add($out, $err); 
    while(my @fhs = $sel->can_read) { 
    foreach my $fh (@fhs) { 
     my $line = <$fh>; 
     unless(defined $line) { 
     $sel->remove($fh); 
     next; 
     } 
     if($fh == $out) { 
     print "[OUTPUT]: $line"; 
     } elsif($fh == $err) { 
     print "[ERROR] : $line"; 
     } else { 
     die "[ERROR]: This should never execute!"; 
     } 
    } 
    } 
    waitpid($pid, 0); 
} 

但上面的代碼工作只在文本模式下,我相信。要使用rtmpdump作爲命令,我需要以二進制模式收集部分輸出,因此不要像上面的代碼一樣逐行讀取STDOUT

STDOUT的二進制輸出應存儲在變量,不打印。

回答

1

使用阻斷功能(例如readline又名<>read,等等)一個select循環內違抗使用select

$sel->add($out, $err); 

my %bufs; 
while ($sel->count) { 
    for my $fh ($sel->can_read) { 
     my $rv = sysread($fh, $bufs{$fh}, 128*1024, length($bufs{$fh})); 

     if (!defined($rv)) { 
     # Error 
     die $! ; 
     } 

     if (!$rv) { 
     # Eof 
     $sel->remove($fh); 
     next; 
     }   

     if ($fh == $err) { 
     while ($bufs{$err} =~ s/^(.*\n)//) { 
      print "[ERROR] $1"; 
     } 
     } 
    } 
} 

print "[ERROR] $bufs{$err}\n" if length($bufs{$err}); 

waitpid($pid, 0); 

... do something with $bufs{$out} ... 

但它會更易於使用IPC::Run

use IPC::Run qw(run); 

my ($out_buf, $err_buf); 
run [ 'sh', '-c', $cmd ], 
    '>', \$out_buf, 
    '2>', sub { 
     $err_buf .= $_[0]; 
     while ($err_buf =~ s/^(.*\n)//) { 
     print "[ERROR] $1"; 
     } 
    }; 

print "[ERROR] $err_buf\n" if length($err_buf); 

... do something with $out_buf ... 
+0

我應該澄清一個問題:除了將STDOUT數據存儲到變量之外,我需要能夠處理這些部分數據,無論何時可用。換句話說,某些功能應該在每次可用時調用新的STDOUT數據。 –

+0

@Ωmega用sub ref –

+0

替換'\ $ out_buf'就像@mpapec所說的,按照STDERR的例子。 – ikegami

1

如果你是一個POSIX系統上,嘗試使用Expect.pm。這正是它設計要解決的問題,它還簡化了向產生的進程發送擊鍵的任務。

+0

謝謝你的回答,但這種解決方案是不是我期待的... –

+0

我很困惑 - 你能解釋一下爲什麼Expect.pm不會解決問題了嗎?或者你是否特別想創建一個「從頭開始」的解決方案而不使用現有的庫? –

相關問題