Perl 无需等待即可读取外部命令的STDOUT和STDERR

Perl 无需等待即可读取外部命令的STDOUT和STDERR,perl,Perl,我想执行外部命令rtmpdump并分别读取它的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";

我想执行外部命令rtmpdump并分别读取它的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用作命令,我需要以二进制模式收集部分输出,因此不要像上面代码中那样逐行读取标准输出


标准输出的二进制输出应该存储在变量中,而不是打印。

如果您使用的是POSIX系统,请尝试使用。这正是它设计用来解决的问题,它还简化了向派生进程发送击键的任务。

在选择循环中使用阻塞功能,例如readline aka、read等,这是无法使用选择的

但使用起来要简单得多


我很困惑-你能解释一下为什么Expect.pm不能解决你的问题吗?或者您特别想在不使用现有库的情况下创建一个从头开始的解决方案?我应该澄清一个问题:除了将标准数据存储到变量之外,我还需要能够在任何可用的情况下处理这些部分数据。换句话说,当某些函数可用时,每次都应该使用新的标准输出数据调用它们@Ω用sub-refLike@mpapec说,用STDERR的例子来替换\$out\u buf。
$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} ...
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 ...