Модераторы: ginnie, korob2001
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Связь программ через pipe, Хитрая задачка 
:(
    Опции темы
Norrator
Дата 19.12.2005, 15:51 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Привет всем!
Существует задача чтения всего вывода (STDOUT) скрипта1 через pipe скриптом2, при этом скрипт1 позволяет пользователю вводить данные с клавиатуры. Скрипт1 работает, но как только выполнить ./скрипт1 | ./скрипт2 появляются проблемы, а именно, сам ввод предшествует приглашению на ввод. В чём проблема?
Усложнение: Скрипт1 править нельзя!!!!

Код

#Скрипт1

open(STDERR ,">&STOUT");
select(STDOUT);
$| = 1;
print STDOUT "HOSTNAME1  :";
$hn = <STDIN>;
.......
close(STDERR);


Код

#Скрипт2

while($str = <>)
{
  print STDOUT "piped_$str";
} 


Это сообщение отредактировал(а) sharq - 19.12.2005, 16:07
  Вверх
sharq
Дата 19.12.2005, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Perl Liker
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 13.12.2004
Где: Ростов-на-Дону

Репутация: 3
Всего: 28



Norrator
Цитата(Norrator @ 19.12.2005, 16:51)
сам ввод предшествует приглашению на ввод. В чём проблема?

Проблема в том, что это не ввод первого скрипта предшествует приглашению,
а ввод второго скрипта:
Цитата(Norrator @ 19.12.2005, 16:51)
$str = <>


Вот полезно будет, работа через pipe.
Цитата

Двустороннее взаимодействие с другим процессом

Если так удобно реализовано однонаправленное взаимодействие, что у нас с двусторонним взаимодействием? Такой очевидный прием на практике не работет:

    open(PROG_FOR_READING_AND_WRITING, "| какая-то программа |")

и если вы забудете указать use warnings или флаг -w, то вы пропустите диагностическое сообщение:

    Can't do bidirectional pipe at -e line 1.
    Невозможно создать двунаправленный канал

Если вам действительно необходим двунаправленный канал, вы можете использовать стандартную библиотечную функцию open2(), чтобы перехватывать ввод и вывод программы. Существует также функция open3() для трехнаправленного ввода/вывода, таким образом вы можете перехватывать STDERR дочернего процесса, но использование этой функции требует последующего неуклюжего цикла select() и не позволяет пользоваться обычными операциями ввода Perl.

Если вы посмотрите исходный код, вы увидите, что open2() использует низкоуровневые примитивы, такие как Unix вызовы pipe() и exec(), для создания всех соединений. Хотя использование этой функции может быть несколько более эффективным, чем socketpair(), она не является такой уж переносимой. Маловероятно, что функции open2() и open3() будут работать где-либо, кроме Unix систем или систем, претендующих на совместимость с POSIX.

Вот пример использования open2():

    use FileHandle;
    use IPC::Open2;
    $pid = open2(*Reader, *Writer, "cat -u -n" );
    print Writer "stuff\n";
    $got = <Reader>;

Здесь имеется проблема, буферизация Unix действительно может испортить вам день. Даже если ваш дескриптор Writer является auto-flushed дескриптором, и процесс на другом конце получает свои данные своевременно, обычно у вас нет никаких средств заставить его возвращать данные также своевременно. Поэтому мы указали cat флаг -u, чтобы сделать вывод небуферизованным. Однако очень мало команд Unix разработано для работы с каналами (pipes), поэтому такой код редко срабатывает, только если вы сами не напишите программу, которая будет работать на другом конце двунаправленного канала.

Решением является использование нестандартной библиотеки Comm.pl. Она использует pseudo-ttys, чтобы сделать поведение вашей программы более корректным:

    require 'Comm.pl';
    $ph = open_proc('cat -n');
    for (1..10) {
        print $ph "строка\n";
        print "получили ответ ", scalar <$ph>;
    }

Таким образом, у вас нет необходимости в доступе к исходному коду используемой программы. Библиотека Comm также содержит функции expect() и interact(). Вы можете найти библиотеку (и, надеемся, ее преемника IPC::Chat) в ближайтем архиве CPAN.

Более новый модуль Expect.pm из CPAN также предназначен для подобных вещей. Этот модуль требует для работы два других модуля из CPAN: IO::Pty и IO::Stty. Он настраивает псевдо-терминалы для взаимодействия с программами, которые работают с драйвером терминального устройства. Если в вашей системе такое поддерживается - этот модуль будет лучшим выбором.



smile

Это сообщение отредактировал(а) sharq - 19.12.2005, 16:42


--------------------
[color=gray]There's More Than One Way To Do It[/color]
PM MAIL WWW ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl: Системное программирование"
korob2001
sharq
  • В этом разделе обсуждаются вопросы относящиеся только к системному программированию на Perl
  • Если ваш вопрос не относится к системному или CGI программированию, задавайте его в общем разделе
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0462 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.