Perl和open3。我错过了什么?

时间:2012-10-11 01:03:38

标签: perl mplayer

我正在尝试创建一个使用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。

1 个答案:

答案 0 :(得分:1)

首先,切换到lexical filehandles。 Typeglobs是全局包,难以使用。

问题在于local *DEVNULL。您已将*DEVNULL置于start_mplayer本地(及其所谓的任何内容,包括open3),但之后使用了相关的文件句柄 start_mplayer。到那时,*DEVNULL已恢复到其全局状态(即空),open3尝试写入空文件句柄。您应该收到print() on unopened filehandle DEVNULL警告,但是您没有警告......

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

或者,您可以让open3写入错误文件句柄,然后忽略它们。浪费了极少量的记忆。

其他变化......

  • 启用严格和警告
  • 从不使用OUTPUT。
  • 将命令分解为多个args可以避免可能的shell干扰。
  • 不需要事先将本地化的文件句柄放入对象中。
  • autodie比输入“或死...”更容易。

这是您重做的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