1

我正在尝试制作一个使用 open3 与 mplayer 通信的脚本,但 mplayer 进程显示为已失效,我无法将标准输入发送到 mplayer。

这是代码:

#!/usr/bin/env perl

{
    package mplayer::test;
    use IPC::Open3;

    sub new {
        my $class = shift;
        my $self = bless { @_ }, $class;
        $self->start_mplayer();
        $self;
    }

    sub start_mplayer{
        my $self = shift;
        local *DEVNULL;
        open DEVNULL, ">/dev/null" or die "/dev/null: $!";
        open OUTPUT, ">out.log" or die "out.log: $!";
        $self->{r} = local *MPLAYER_READ;
        $self->{w} = local *MPLAYER_WRITE;
        $self->{pid} = open3($self->{w},$self->{r},">&DEVNULL",'mplayer -slave -idle -v');
        die "Error opening mplayer!\n" unless $self->{pid};
    }
    sub do{
        my ($self, $command) = @_;
        print {$self->{w}} $command, "\n";
    }
}

mplayer::test->new;

mplayer::test->do(qq~loadfile test.mp3~);
sleep(5);

我一定遗漏了一些明显的东西,我正在从其他模块的示例中学习 open3。

4

1 回答 1

1

首先,切换到词法文件句柄。Typeglob 是全局包,很难使用。

一个问题是local *DEVNULL. 您已将其*DEVNULL设为本地start_mplayer(以及它所调用的任何内容,包括open3),但随后 start_mplayer. 到那时,*DEVNULL已恢复到其全局状态(即空)并open3尝试写入空文件句柄。你应该得到一个print() on unopened filehandle DEVNULL警告,但你没有警告...

解决方案:不要本地化它。不幸的是,这意味着您不能同时运行多个 mplayer 实例。通常你会通过使用词法文件句柄来解决这个问题,但不幸的是,特殊>&语法只适用于全局句柄。解决方案是只打开一次 DEVNULL。

或者,您可以让open3写入错误文件句柄并忽略它们。浪费极少的内存。

其他变化...

  • 开启严格和警告
  • OUTPUT 从未使用过。
  • 将命令分解为多个参数可以避免可能的 shell 干扰。
  • 事先将本地化的文件句柄放入对象中是不必要的。
  • autodie 比一直输入“or die ...”更容易。

这是你重新设计的start_mplayer例程。我没有可以试用的 mplayer 副本,但可以正常使用cat.

use strict;
use warnings;
use autodie;

sub start_mplayer{
    my $self = shift;

    # Only open DEVNULL once, since its going to be shared.
    open DEVNULL, ">", /dev/null" unless fileno DEVNULL;

    $self->{pid} = open3($self->{r}, $self->{w}, ">&DEVNULL", 'mplayer', '-slave', '-idle', '-v');

    die "Error opening mplayer!\n" unless $self->{pid};
}

要确定它是您的程序还是 mplayer 的某些奇怪之处,请尝试使用不同的命令,例如“cat”。通常你必须关闭输入,或者确保它看到换行符,然后程序才会产生输出。

有关与程序交互的更强大的方式,请参阅IPC::Run

于 2012-10-11T05:40:14.600 回答