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

まず、レキシカル ファイルハンドルに切り替えます。型グロブはパッケージ グローバルであり、操作が困難です。

1 つの問題がありlocal *DEVNULLます。*DEVNULLローカルstart_mplayer(および を含む、それが呼び出すもの) を作成しましopen3たが、関連付けられたファイルハンドルを の外部で start_mplayer使用しました。その時まで*DEVNULLに、グローバル状態 (つまり、空) に戻りopen3、空のファイルハンドルに書き込もうとします。警告が表示されているはずですが、print() on unopened filehandle DEVNULL警告が表示されていません...

解決策: ローカライズしないでください。残念ながら、これは一度に複数の mplayer インスタンスを実行できないことを意味します。通常、レキシカル ファイルハンドルを使用してこれを解決しますが、残念ながら特殊な>&構文はグロブ ハンドルでしか機能しません。解決策は、DEVNULL を 1 回だけ開くことです。

open3の方法として、エラー ファイルハンドルへの書き込みを許可し、それらを無視することもできます。わずかな量のメモリを浪費します。

その他の変更...

  • 厳密と警告をオンにする
  • OUTPUT は使用されません。
  • コマンドを複数の引数に分割すると、シェルの干渉を回避できます。
  • ローカライズされたファイルハンドルを事前にオブジェクトに入れる必要はありません。
  • 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 に答える