Как я могу использовать Perl для запуска программы Win32 и перенаправить ее вывод на стандартный вывод? - PullRequest
1 голос
/ 14 декабря 2009

У меня есть кроссплатформенная Perl-программа, которая запускает win32-windows-программу на win, и приложение macosx на mac.

Я использую system(), который на Mac превращает стандартный вывод вызываемой программы в стандартный вывод Perl-программы, чего я и хочу.

В Windows кажется, что нет способа получить стандартный вывод программы Windows. В качестве альтернативы, вместо этого у меня есть программа записи в файл журнала, и я бы хотел, чтобы Perl читал из файла журнала (в момент записи вызванная программа могла работать в течение часа) и перенаправлял ее обратно в Stlout Perl, так что опыт работы на Win и Mac одинаков.

Кто-нибудь знает, как на самом деле сделать это в Perl? Я думаю:

  • форк процесс
  • File :: Tail лог-файла, запись в stdout при поступлении данных
  • каким-то образом выяснить, когда программа фактически закончила работать.

Я, наверное, могу понять № 1 и № 2, но пока не знаю, как справиться с № 3.

Ответы [ 6 ]

4 голосов
/ 14 декабря 2009

Будет ли следующее соответствовать вашему первоначальному намерению: stdout программы win32 также stdout из perl (или я неправильно понял ваш первоначальный вопрос)?

// Win32 console application printing to stdout
#include <stdio.h>

int main(int argc, char* argv[])
{
    int idx;
    for (idx=0; idx < 10; idx++) {
        printf("Hello World!\n");
        fflush(stdout);
    }
    return 0;
}

Perl-программа захватывает stdout программ Windows и перенаправляет на stdout:

use strict; use warnings;

my $cmd = "Debug/hello.exe";
open my $cmd_h, "$cmd |" or die "Cannot open pipe to '$cmd': $!";
print "Perl:$_" while <$cmd_h>;
close $cmd_h or die "Cannot close pipe to '$cmd': $!";
2 голосов
/ 14 декабря 2009

IPC::Run3 позволяет вам предоставлять данные для stdin и захвата stdout и stderr.

2 голосов
/ 14 декабря 2009

Если вам нужно захватить выходные данные, которые ваши программы печатают в STDOUT, почему бы вам просто не использовать обратные пометки вместо system()?

my $stdout = `program_name`;
if ( $? ) {
    print "Child process had an error";
}
0 голосов
/ 14 декабря 2009

Не совсем понятно, что вы подразумеваете под «получить стандартный вывод», но это правильно выводит «foo» в стандартный вывод при запуске perl.exe из командной строки Windows:

perl -e "system 'echo foo'"

Так что я думаю, что пока вы запускаете Perl в командном окне и не пытаетесь связываться с какими-либо дескрипторами файлов stdout перед вызовом system, это должно работать.

0 голосов
/ 14 декабря 2009

Захватите возвращаемое значение вызова fork, чтобы получить идентификатор процесса дочернего процесса.

my $pid = fork();
if ($pid == 0) { # child
    system("command > logfile");
    exit 0;
}
# else parent
do {
    # ... apply File::Tail to logfile, print new output ... 
while (process_is_active($pid));

Тогда есть много способов узнать, когда ребенок закончил. Вот два:

# 1. kill 0, $pid
sub process_is_active {
    my ($pid) = @_;
    return kill 0, $pid;  # returns "number of processes successfully signalled"
}

В некоторых системах реализована kill 0,... лучше, чем в других.

# 2. non-blocking waitpid 
sub process_is_active {
    use POSIX ':sys_wait_h';
    my ($pid) = @_;
    my $waitpid = waitpid $pid, WNOHANG;
    return $waitpid == $pid;
}

Второе решение будет работать только один раз - после того, как waitpid обнаружит, что процесс завершен и пожнет его, он вернет -1, если вы вызовете его снова в этом процессе.

0 голосов
/ 14 декабря 2009

Вы читали документы по системе ? system не позволяет вам захватить STDOUT. qx делает.

С другой стороны, не похоже, что вы действительно хотите захватить STDOUT. Похоже, вы хотите, чтобы вывод программы отображался в том же окне терминала, что и программа Perl. Если программа, которую вы вызываете в Windows, печатает свой вывод в STDOUT, и если вы запускаете свою программу Perl в окне cmd, то это произойдет естественным образом.

...