1

我想执行外部命令并单独rtmpdump读取它,但不要等到这样的命令结束,而是在可用时批量读取它的部分输出......STDOUTSTDERR

在 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 的二进制输出应存储在变量中,而不是打印。

4

2 回答 2

1

如果您使用的是 POSIX 系统,请尝试使用Expect.pm。这正是它旨在解决的问题,它还简化了将击键发送到衍生进程的任务。

于 2013-06-18T17:47:01.203 回答
1

在循环中使用阻塞函数(例如readlineaka <>read等)违反了使用.selectselect

$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 ...
于 2013-06-20T18:01:43.920 回答