捕获程序的标准输出和标准错误并分别存储在变量中

23 浏览
0 Comments

捕获程序的标准输出和标准错误并分别存储在变量中

在一次运行中,是否可以将外部程序的stdout重定向到一个变量,将外部程序的stderr重定向到另一个变量?

例如:

$global:ERRORS = @();
$global:PROGERR = @();
function test() {
    # 在这里,我们能否将错误重定向到$PROGERR变量,将stdout保留给$OUTPUT变量?
    $OUTPUT = (& myprogram.exe 'argv[0]', 'argv[1]');
    if ( $OUTPUT | select-string -Pattern "foo" ) {
        # 做一些操作
    } else {
        $global:ERRORS += "test(): oh noes! 'foo' missing!";
    }
}
test;
if ( @($global:ERRORS).length -gt 0 ) {
    Write-Host "脚本特定错误发生";
    foreach ( $err in $global:ERRORS ) {
        $host.ui.WriteErrorLine("err: $err");
    }
} else {
    Write-Host "脚本运行正常!";
}
if ( @($global:PROGERR).length -gt 0 ) {
    # 做一些操作
} else {
    Write-Host "外部程序运行正常!";
}

一个乏味的例子,不过我想知道是否可以实现这个功能?

0
0 Comments

问题的原因是使用Start-Process命令时,没有正确设置-RedirectStandardError和-RedirectStandardOutput选项,导致无法将程序的标准输出和标准错误分别捕获到不同的变量中。解决方法是按照以下示例代码设置正确的选项和顺序:

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "ping.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "localhost"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
$p.WaitForExit()
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
Write-Host "exit code: " + $p.ExitCode

此外,如果应用程序没有异步写入标准错误和标准输出,这段代码可能会导致死锁。为了解决这个问题,可以将WaitForExit()方法调用放在ReadToEnd()方法调用之后,即按照以下链接中所建议的方法进行调整:[http://stackoverflow.com/a/11549817/1127485](http://stackoverflow.com/a/11549817/1127485)

0
0 Comments

从上述内容中,我们可以总结出问题的原因是要将程序的stdout和stderr分别捕获到不同的变量中。而解决方法是使用一个文件来保存stderr的输出,并通过读取文件内容将其保存到变量中。

在给出的示例中,使用了一个名为"stderr.txt"的文件来保存stderr的输出。首先,通过运行命令& myprogram.exe 'argv[0]', 'argv[1]' 2>stderr.txt来执行程序,并将stderr的输出重定向到"stderr.txt"文件中。接下来,通过get-content stderr.txt命令将文件内容读取到变量"$err"中。最后,通过检查"$LastExitCode"的值,我们可以判断程序是否出现错误,并进行相应处理。

作者还建议使用"$LastExitCode"来检查从原生控制台EXE文件返回的错误。此外,作者还指出,对于stderr来说,输出的内容并不是命令本身产生的内容,而是主机对命令产生的内容的报告,这对于其他背景的用户可能会让人感到惊讶。

最后,作者提到了一个有用的工具New-TemporaryFile,它可以方便地创建一个临时文件,这对于使用一次就不再需要的"stderr.txt"文件非常有用。

0
0 Comments

问题的原因是需要将程序的标准输出(stdout)和标准错误输出(stderr)分别捕获到不同的变量中。解决方法是通过将stdout和stderr合并成一个流,然后进行过滤。

首先,将程序的输出存储到一个变量中:

$allOutput = & myprogram.exe 2>&1

然后,通过筛选判断对象的类型,将stderr和stdout分别存储到不同的变量中:

$stderr = $allOutput | ?{ $_ -is [System.Management.Automation.ErrorRecord] }
$stdout = $allOutput | ?{ $_ -isnot [System.Management.Automation.ErrorRecord] }

更好的方法是使用管道符号和tee命令将输出打印到屏幕上,并将所有输出存储到一个变量中:

& myprogram.exe 2>&1 | tee -Variable allOutput

这样可以免费打印输出,并且保持stdout和stderr交错输出的顺序。这种方法也不需要通过文件,从而提高了性能并减少了可能出错的地方。

还可以结合捕获输出到变量中的方法,不输出到屏幕上:

[Void] (& myprog.exe 2>&1 | tee -Variable allOutput)

然后,通过判断对象的类型,将stdout存储到一个变量中:

$stdout = $allOutput | ?{ $_ -isnot [System.Management.Automation.ErrorRecord] }

通过以上方法,可以将程序的stdout和stderr分别捕获到不同的变量中,方便后续的处理和分析。同时,通过tee命令将输出打印到屏幕上,保持输出顺序的一致性,提高了程序的性能和稳定性。

0