Powershell не захватывает стандартный вывод Perl - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть следующий простой скрипт в powershell (скажем, под C:\Users\myusername\Desktop\tests\test.ps1)

$counter = 0
while (1) {
    $counter++
    if ($counter % 2) {
        [Console]::Error.WriteLine("($counter) This is an error")
    } else {
        echo "($counter) Some output"
    }
    sleep 1
}

Я хочу программно вызвать этот скрипт и записать его стандартный вывод и стандартную ошибку в файл (скажем, C:\Users\myusername\Desktop\test.log).Для этого я написал следующий скрипт powershell:

$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = 'C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe'
$psi.Arguments = @('C:\Users\myusername\Desktop\tests\test.ps1')

$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi

$logAction = {
    $time = Get-Date -Format o
    Add-Content 'C:\Users\myusername\Desktop\test.log' "($time)[$($Event.MessageData)]: $($Event.SourceArgs.Data)"
}

Register-ObjectEvent -InputObject $process -EventName ErrorDataReceived -Action $logAction -MessageData "STDERR" >$null
Register-ObjectEvent -InputObject $process -EventName OutputDataReceived -Action $logAction -MessageData "STDOUT" >$null

$process.Start() >$null
$process.BeginErrorReadLine() >$null
$process.BeginOutputReadLine() >$null

$process.Id

Содержимое файла test.log соответствует ожидаемому:

(2018-12-05T15:00:45.7615056+01:00)[STDERR]: (1) This is an error
(2018-12-05T15:00:47.0119743+01:00)[STDOUT]: (2) Some output
(2018-12-05T15:00:47.9497710+01:00)[STDERR]: (3) This is an error
(2018-12-05T15:00:49.8253980+01:00)[STDOUT]: (4) Some output
(2018-12-05T15:00:49.8253980+01:00)[STDERR]: (5) This is an error
(2018-12-05T15:00:51.2008546+01:00)[STDOUT]: (6) Some output
(2018-12-05T15:00:51.8260768+01:00)[STDERR]: (7) This is an error
(2018-12-05T15:01:03.6269252+01:00)[STDERR]:
(2018-12-05T15:01:03.6269252+01:00)[STDOUT]:

Но теперь возникает интересная часть.У меня есть следующий скрипт perl (скажем, под C:\Users\myusername\Desktop\tests\test.pl), который я запускаю в Windows, используя Strawberry Perl , и который очень похож на первый скрипт powershell в моем вопросе:

#!/usr/bin/perl

use strict;
use warnings;

my $counter = 0;

while (1) {
    $counter++;

    if ($counter % 2) {
        print STDERR "($counter) This is an error!\n";
    } else {
        print STDOUT "($counter) Some message\n";
    }

    sleep 1;
}

Я также хочу программно вызвать этот скрипт и записать его стандартный вывод и стандартную ошибку в файл.Для этого я меняю второй скрипт в моем вопросе, обновляя значения $psi.FileName и $psi.Arguments до:

$psi.FileName = 'C:\Strawberry\perl\bin\perl.exe'
$psi.Arguments = @('C:\Users\myusername\Desktop\tests\test.pl')

Но теперь содержимое файла test.log не соответствует ожиданиям

(2018-12-05T14:14:53.9176561+01:00)[STDERR]: (1) This is an error!
(2018-12-05T14:14:55.7926306+01:00)[STDERR]: (3) This is an error!
(2018-12-05T14:14:57.9801317+01:00)[STDERR]: (5) This is an error!
(2018-12-05T14:15:22.2301618+01:00)[STDOUT]:
(2018-12-05T14:15:22.2301618+01:00)[STDERR]:

Как видите, стандартный вывод не захватывается.Я понятия не имею, почему это происходит и как я могу это решить.Почему это не работает для Perl, но это для PowerShell?Как мне заставить его работать с perl?

Моя версия powershell 5.1.17134.407 на Windows 10 Pro.

1 Ответ

0 голосов
/ 05 декабря 2018

STDERR обычно устанавливается для автоматической промывки, STDOUT - нет.Ваш код ожидает получения каждой выходной строки в том виде, в каком она написана.

Попробуйте добавить следующие 2 строки в ваш Perl-скрипт после use warnings;

use IO::Handle;
STDOUT->autoflush(1);
...