2012-10-11 4 views
1

Я пытаюсь создать сценарий, который взаимодействует с mplayer с помощью open3, но процесс mplayer появляется как несуществующий, и я не могу отправить стандартный ввод в mplayer.Perl и open3. Что мне не хватает?

Вот код:

#!/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 с примерами из других модулей.

+0

''> & DEVNULL "' должно быть '\ * DEVNULL'? –

+0

Нет, '"> & DEVNULL "' правильно – ikegami

+0

Избавиться от '$ self -> {r} = local * MPLAYER_READ; $ self -> {w} = local * MPLAYER_WRITE; 'Если это не поможет, он по крайней мере избавится от двух бесполезных строк. – ikegami

ответ

1

Прежде всего, переключитесь на lexical filehandles. Typeglobs являются глобальными пакетами и с ними трудно работать.

Одна проблема с local *DEVNULL. Вы сделали *DEVNULL по местному адресу start_mplayer (и все, что он называет, включая open3), но затем использовали связанные с ним файловые дескрипторы снаружиstart_mplayer. К этому времени *DEVNULL вернулась в свое глобальное состояние (то есть пустое) и open3 пытается записать пустую дескриптор файла. Вы должны были получить предупреждение print() on unopened filehandle DEVNULL, но у вас нет предупреждений о ...

Решение: не локализовать его. К сожалению, это означает, что вы не можете одновременно запускать несколько экземпляров mplayer. Обычно вы решаете это с помощью лексического дескриптора файла, но, к сожалению, специальный синтаксис >& работает только с ручками glob. Решение состоит только в том, чтобы разобрать DEVNULL один раз.

В качестве альтернативы вы можете сообщить open3 записи об ошибке и просто игнорировать их. Отбрасывает минимальный объем памяти.

Другие изменения ...

  • Включите строги и предупреждения
  • OUTPUT никогда не используется.
  • Разбивание команды на несколько аргументов позволяет избежать возможных помех оболочки.
  • Ввод локализованных дескрипторов файлов в объект заранее не требуется.
  • 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, попробуйте другую команду, как «кошка». Зачастую вам нужно закрыть вход или убедиться, что он видит новую строку, прежде чем программа выдаст результат.

Для более надежного способа взаимодействия с программами см. IPC::Run.

Смежные вопросы