捕获程序stdout和stderr以分隔变量

问题描述 投票:34回答:4

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

例如:

$global:ERRORS = @();
$global:PROGERR = @();

function test() {
    # Can we redirect errors to $PROGERR here, leaving stdout for $OUTPUT?
    $OUTPUT = (& myprogram.exe 'argv[0]', 'argv[1]');

    if ( $OUTPUT | select-string -Pattern "foo" ) {
        # do stuff
    } else {
        $global:ERRORS += "test(): oh noes! 'foo' missing!";
    }
}

test;
if ( @($global:ERRORS).length -gt 0 ) {
    Write-Host "Script specific error occurred";
    foreach ( $err in $global:ERRORS ) {
        $host.ui.WriteErrorLine("err: $err");
    }
} else {
    Write-Host "Script ran fine!";
}

if ( @($global:PROGERR).length -gt 0 ) {
    # do stuff
} else {
    Write-Host "External program ran fine!";
}

一个沉闷的例子,但我想知道这是否可能?

windows powershell command-line stdout stderr
4个回答
12
投票

最简单的方法是使用stderr输出的文件,例如:

$output = & myprogram.exe 'argv[0]', 'argv[1]' 2>stderr.txt
$err = get-content stderr.txt
if ($LastExitCode -ne 0) { ... handle error ... }

我还会使用$ LastExitCode来检查本机控制台EXE文件中的错误。


33
投票

一种选择是将stdout和stderr的输出组合成单个流,然后过滤。

来自stdout的数据将是字符串,而stderr则生成System.Management.Automation.ErrorRecord对象。

$allOutput = & myprogram.exe 2>&1
$stderr = $allOutput | ?{ $_ -is [System.Management.Automation.ErrorRecord] }
$stdout = $allOutput | ?{ $_ -isnot [System.Management.Automation.ErrorRecord] }

8
投票

您应该使用带有-RedirectStandardError -RedirectStandardOutput选项的Start-Process。这个other post有一个很好的例子,如何做到这一点(从下面的帖子中抽样):

$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
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
Write-Host "exit code: " + $p.ExitCode

2
投票

这也是我用来重定向命令行的stdout和stderr同时在PowerShell执行期间仍然显示输出的替代方法:

$command = "myexecutable.exe my command line params"

Invoke-Expression $command -OutVariable output -ErrorVariable errors
Write-Host "STDOUT"
Write-Host $output
Write-Host "STDERR"
Write-Host $errors

这是补充已经给出的补充的另一种可能性。

请记住,这可能并不总是有效,具体取决于脚本的调用方式。从标准命令行而不是像这样的PowerShell命令行调用时,我遇到了-OutVariable和-ErrorVariable的问题:

PowerShell -File ".\FileName.ps1"

在大多数情况下似乎有效的替代方案是:

$stdOutAndError = Invoke-Expression "$command 2>&1"

不幸的是,在执行脚本期间,您将丢失输出到命令行,并且在命令返回后必须使用Write-Host $stdOutAndError使其成为“记录的一部分”(就像运行Jenkins批处理文件的一部分一样)。不幸的是,它没有将stdout和stderr分开。

© www.soinside.com 2019 - 2024. All rights reserved.