Powershell 不捕获 perl 的标准输出

Powershell not capturing perl's standard output

我在 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 版本是 Windows 10 Pro 上的 5.1.17134.407。

STDERR 通常设置为自动刷新,STDOUT 不是。您的代码期望在写入时接收到每一行输出。

尝试在 use warnings;

之后将以下两行添加到您的 Perl 脚本中
use IO::Handle;
STDOUT->autoflush(1);