web-dev-qa-db-ja.com

プログラムstdoutとstderrをキャプチャして変数を分離する

Stdoutを外部プログラムから変数にリダイレクトし、stderrを外部プログラムから別の変数に1回の実行でリダイレクトすることは可能ですか?

例えば:

$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!";
}

退屈な例ですが、それが可能かどうか疑問に思っていますか?

36
dusz

これを行う最も簡単な方法は、stderr出力用のファイルを使用することです。例:

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

また、$ LastExitCodeを使用して、ネイティブコンソールEXEファイルのエラーをチェックします。

12
Keith Hill

1つのオプションは、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] }
34
Aaron Schultz

-RedirectStandardError -RedirectStandardOutputオプションを指定してStart-Processを使用する必要があります。この 他の投稿 には、これを行う方法の素晴らしい例があります(以下の投稿からサンプリング):

$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
8
AckSynFool

これは、PowerShellの実行中に出力を表示しながら、コマンドラインのstdoutとstderrをリダイレクトするために使用した代替手段でもあります。

$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は区別されません。

3
James Eby