Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Фильтр внутри фильтра


Автор: amg 21.4.2007, 16:10
Мой скрипт получает данные с stdin и пишет на stdout. Внутри скрипта вызывается внешняя программа-фильтр, которая тоже получает данные с stdin и пишет их на stdout. 
Помогите реализовать (без использования временных файлов). Что-то я совсем запутался с STDIN и STDOUT-ами.

Автор: Nab 21.4.2007, 16:49
Не понятен вопрос, нужно перехватывать вывод, или что?
Какое поведение реализовать не удаеться?

Автор: amg 21.4.2007, 20:24
Попробую по-подробнее, на примере с использованием временных файлов.
Нужно то же самое, но без использования временных файлов.
Код

# Программа-фильтр. Для примера, пусть это будет вычисление длины строки.
$filtr = qq(perl -lne "print length");

while (<STDIN>) {
  # Скрипт получает с stdin очередную строку. 

  # Модифицирует ее как-то

  # Пропускает модифицированную строку через фильтр
  open IN, '>file.in';
  print IN $_;
  close IN;
  system("cat file.in | $filtr > file.out");
  open OUT, 'file.out';
  $filtred = <OUT>;
  close OUT;

  # Модифицируется $filtred

  # результат выводится на stdout
  print "$filtred";
}

Автор: Nab 21.4.2007, 22:21
amg, вот погляди вот здесь
http://forum.vingrad.ru/index.php?showtopic=125785&view=findpost&p=950681
если вопросы еще остануться, пиши, а то я уже устал сегодня, спать пойду smile

Автор: amg 23.4.2007, 14:37
Пока вот что у меня получилось:
Код

use IPC::Open2;

$filtr = qq(perl -lne "print length");

while (<STDIN>) {
  open2(\*Reader, \*Writer, "$filtr" );
  
  print Writer "$_\n";
  close Writer;
  
  $filtred = <Reader>;
  close Reader;
  
  print "$filtred";
}

Не нравится. На каждую строку - новый процесс. В предыдущем варианте было на каждую строку - новый файл. Даже не знаю, что хуже.

Автор: Nab 23.4.2007, 16:02
Вот так у меня получилось, все пашет норм, и отключение буферизации во внутреннем вызове ключевой момент smile
Код

use strict;
use warnings;

use IPC::Open2;

$|++;

my $filtr = q(perl -ne "$|=1; print length, $_");
my $filtred = '';

open2(\*Reader, \*Writer, $filtr );

while (<>) {

  print Writer "$_";

  $filtred = <Reader>;

  print "$filtred";
}
close Writer;
close Reader;

1;


Автор: amg 24.4.2007, 06:17
Nab, что-то у меня не работает твой код. Запускаю на linux script.pl file.txt. Ничего не печатает, ждет stdin. И еще, боюсь, с отключением буферизации во внутреннем вызове возможны проблемы - в качестве внутреннего фильтра ($filtr) будет программа, исходников которой у меня нет.

Автор: Nab 24.4.2007, 08:40
Ага, ну так там же кавычки первым делом другие, и вот я для линукса переписал:
Код

#!/usr/bin/perl

use strict;
use warnings;

use IPC::Open2;

$|++;

my $filtr = q(/usr/bin/perl -ne '$|=1; print length, $_');
my $filtred = '';
my ($wrh, $rdh);

open2($rdh, $wrh, $filtr);

while (<>) {

    print $wrh "$_";

    $filtred = <$rdh>;

    print $filtred;
}
close $wrh;
close $rdh;

1;


Добавлено через 1 минуту и 46 секунд
А на счет буферизации, то это в конкретном примере важно smile, оно и без нее пашет, но ждет долше smile

Автор: amg 24.4.2007, 09:30
Да уж, про кавычки я и сам мог бы догадаться.
С правильными кавычками работает! Любопытно, что возвращаемая фильтром строка должна заканчиваться на "\n", иначе не работает.
А с буферизизацией буду пробовать, как оно себя поведет на реальном фильтре.

Nab, спасибо огромное!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)