Как посмотреть STDOUT запущенной программы из программы perl, которая его вызвала? - PullRequest
6 голосов
/ 09 февраля 2012

Мы пытаемся выяснить, как запустить java-приложение из perl-скрипта, но все еще можем периодически читать из STDOUT java-приложения.

print "running dcmrcv.bat\n";

open my $fh_dcmrcv, "-|", 'z:\apps\dcm4che\dcm4che-2.0.26\bin\dcmrcv.bat \
  DCMRCV:11112 -dest z:\dcmrcv -journal z:\dcmrcv', 
  or die "could not execute dcmrcv: $!";

print "dcmrcv.bat started\n";

Мы хотели иметь возможность читатьиз файлового дескриптора, $ fh_dmcrcv, каждые несколько минут или, возможно, путем установки триггера AnyEvent io, когда есть активность в файловом дескрипторе.

Однако, когда я пытаюсь читать из файлового дескриптора, он блокируется, если я что-то используюкак это:

foreach my $line (<$fh_dmcrcv>) {
  print $line;
}

Мы попробовали несколько подходов, не думайте, что мы можем использовать File :: Tail, так как кажется, что модулю нужен фактический файл.Кажется, проблема в том, что $ fh_dcmrcv блокирует нас, когда мы читаем из него, не совсем уверенный в правильном подходе к тому, как добиться того, чего мы хотим.

РЕДАКТИРОВАТЬ # 1

Когда мы запускаем наш Perl-скрипт, мы видим вывод наподобие этого:

Z:\projects\demo_2>process_files.pl
running dcmrcv.bat
dcmrcv.bat started
Start Server listening on port 11112
11:55:13,495 INFO   - Start listening on 0.0.0.0/0.0.0.0:11112

Сценарий, process_files.pl, отправляет сообщения msg .:

running dcmrcv.bat
dcmrcv.bat started

Сообщения.из java-программы: Запустите прослушивание сервера на порту 11112 11: 55: 13,495 INFO - Начните прослушивание на 0.0.0.0/0.0.0.0:11112

В этом случае мы выводим эти сообщения только радиэтого вопроса, на самом деле мы хотим периодически анализировать определенные сообщения.и никогда не повторяйте ни одного из них.

Любое понимание приветствуется,

-Sam

Ответы [ 3 ]

4 голосов
/ 09 февраля 2012

Большинство систем поддерживают функцию select с четырьмя аргументами (также хорошо упакованную в IO::Select), которая может сказать вам, есть ли ожидание ввода на дескрипторе сокета или дескрипторе канала.В Windows select поддерживается только в сокетах, что приводит к византийскому решению:

  1. Создайте пару сокетов
  2. Форк и выполните команду в дочернем процессе
  3. В дочернем процессе извлеките выходные данные команды и запишите их в сокет
  4. В родительском процессе используйте операции выбора и чтения для сокета по своему усмотрению

Пример:

use Socket;
use IO::Select;
use Time::HiRes;
$cmd = $^X . ' -MMath::BigInt -e "$_=1; '
       . 'print qq/$_!=/,Math::BigInt->new($_)->bfac(),qq/\n\n\n/'
       . ' for 4000..4100"';
socketpair A,B,AF_UNIX,SOCK_STREAM,PF_UNSPEC;  # step 1
if (fork() == 0) {
    open my $fh, '-|', $cmd;                   # step 2
    while (<$fh>) {
        print B;                               # step 3
    }
    close $fh;
    exit $? >> 8;
}
$s = IO::Select->new();
$s->add(\*A);
for (;;) {
    if ($s->can_read(0.25)) {                  # step 4
        $line = <A>;
        print "Do something with command output: $line";
    } else {
        print "No output now. Could be doing something else ...\n";
        Time::HiRes::sleep(0.25);
    }
}

Вы уверены, что не хотите просто записывать вывод своей команды во временный файл?

2 голосов
/ 09 февраля 2012

Используйте IO :: Select или четырех аргумент select() для чтения, когда чтение не будет блокироваться. РЕДАКТИРОВАТЬ : Неважно, вы в Windows , так что это не сработает. Один из вариантов: иметь процесс-посредник, считываемый из этого канала, и сохранять файл-посредник заполненным любой необходимой вам длиной хвоста. BLEH.

Тем не менее, лучший способ читать "каждые несколько минут" из канала - это читать из него каждые несколько секунд.

0 голосов
/ 09 февраля 2012

Попробуйте читать с этим вместо:

while (my $line = <$fh_dmcrcv>) {
   print $line;
}

привет

...