프로그램 stdout 및 stderr을 개별 변수로 캡처
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!";
}
재미없는 예인데, 그게 가능한지 궁금합니다.
한 가지 옵션은 stdout과 stderr의 출력을 단일 스트림으로 결합한 다음 필터링하는 것입니다.
stdout의 데이터는 문자열이 되며 stderr는 시스템을 생성합니다.관리.자동화.개체 기록 오류.
$allOutput = & myprogram.exe 2>&1
$stderr = $allOutput | ?{ $_ -is [System.Management.Automation.ErrorRecord] }
$stdout = $allOutput | ?{ $_ -isnot [System.Management.Automation.ErrorRecord] }
가장 쉬운 방법은 stderr 출력에 파일을 사용하는 것입니다. 예:
$output = & myprogram.exe 'argv[0]', 'argv[1]' 2>stderr.txt
$err = get-content stderr.txt
if ($LastExitCode -ne 0) { ... handle error ... }
또한 $LastExitCode를 사용하여 네이티브 콘솔 EXE 파일의 오류를 확인하고자 합니다.
Start-Process with -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
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
Write-Host "exit code: " + $p.ExitCode
이는 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를 분리하지 않습니다.
PowerShell 스크립트에서 함수 이름을 가져오고 함수 이름을 전달하려는 경우 dot sourcing을 사용하여 함수 이름과 매개 변수를 호출할 수 있습니다.
해서 를 구하면,$output
면$errors
.
.ps1
파일이 호출됩니다.W:\Path With Spaces\Get-Something.ps1
내부에 기능이 있는Get-It
변수 δFilePath
.
두 경로 모두 따옴표로 감싸어 명령을 위반하는 경로의 공백을 방지합니다.
$command = '. "C:\Path Spaces\Get-Something.ps1"; Get-It -FilePath "W:\Apps\settings.json"'
Invoke-Expression $command -OutVariable output -ErrorVariable errors | Out-Null
# This will get its output.
$output
# This will output the errors.
$errors
출력 정보와 세부 정보를 다른 변수에 모두 캡처하는 방법에 대한 답변을 복사했습니다.
사용.Where-Object
(별명은 기호입니다.?
)은 명백한 방법이지만 너무 번거롭습니다.많은 코드가 필요합니다.
이렇게 하면 시간이 더 오래 걸릴 뿐만 아니라 오류가 발생할 확률도 높아집니다.
실제로 PowerShell에서 서로 다른 스트림을 서로 다른 변수로 분리하는 보다 간결한 방법이 있습니다(실수로 저에게 왔습니다).
# First, declare a method that outputs both streams at the same time.
function thisFunc {
[cmdletbinding()]
param()
Write-Output 'Output'
Write-Verbose 'Verbose'
}
# The separation is done in a single statement.Our goal has been achieved.
$VerboseStream = (thisFunc -Verbose | Tee-Object -Variable 'String' | Out-Null) 4>&1
그 다음 이 두 변수의 내용을 확인합니다.
$VerboseStream.getType().FullName
$String.getType().FullName
콘솔에 다음 정보가 표시됩니다.
PS> System.Management.Automation.VerboseRecord
System.String
'4>&1'은 장황한 스트림을 성공 스트림으로 리디렉션하는 것을 의미하며, 이 스트림을 변수에 저장할 수 있습니다. 물론 이 숫자를 2에서 5 사이의 임의의 숫자로 변경할 수 있습니다.
별도로 서식 보존
cls
function GetAnsVal {
param([Parameter(Mandatory=$true, ValueFromPipeline=$true)][System.Object[]][AllowEmptyString()]$Output,
[Parameter(Mandatory=$false, ValueFromPipeline=$true)][System.String]$firstEncNew="UTF-8",
[Parameter(Mandatory=$false, ValueFromPipeline=$true)][System.String]$secondEncNew="CP866"
)
function ConvertTo-Encoding ([string]$From, [string]$To){#"UTF-8" "CP866" "ASCII" "windows-1251"
Begin{
$encFrom = [System.Text.Encoding]::GetEncoding($from)
$encTo = [System.Text.Encoding]::GetEncoding($to)
}
Process{
$Text=($_).ToString()
$bytes = $encTo.GetBytes($Text)
$bytes = [System.Text.Encoding]::Convert($encFrom, $encTo, $bytes)
$encTo.GetString($bytes)
}
}
$all = New-Object System.Collections.Generic.List[System.Object];
$exception = New-Object System.Collections.Generic.List[System.Object];
$stderr = New-Object System.Collections.Generic.List[System.Object];
$stdout = New-Object System.Collections.Generic.List[System.Object]
$i = 0;$Output | % {
if ($_ -ne $null){
if ($_.GetType().FullName -ne 'System.Management.Automation.ErrorRecord'){
if ($_.Exception.message -ne $null){$Temp=$_.Exception.message | ConvertTo-Encoding $firstEncNew $secondEncNew;$all.Add($Temp);$exception.Add($Temp)}
elseif ($_ -ne $null){$Temp=$_ | ConvertTo-Encoding $firstEncNew $secondEncNew;$all.Add($Temp);$stdout.Add($Temp)}
} else {
#if (MyNonTerminatingError.Exception is AccessDeniedException)
$Temp=$_.Exception.message | ConvertTo-Encoding $firstEncNew $secondEncNew;
$all.Add($Temp);$stderr.Add($Temp)
}
}
$i++
}
[hashtable]$return = @{}
$return.Meta0=$all;$return.Meta1=$exception;$return.Meta2=$stderr;$return.Meta3=$stdout;
return $return
}
Add-Type -AssemblyName System.Windows.Forms;
& C:\Windows\System32\curl.exe 'api.ipify.org/?format=plain' 2>&1 | set-variable Output;
$r = & GetAnsVal $Output
$Meta2=""
foreach ($el in $r.Meta2){
$Meta2+=$el
}
$Meta2=($Meta2 -split "[`r`n]") -join "`n"
$Meta2=($Meta2 -split "[`n]{2,}") -join "`n"
[Console]::Write("stderr:`n");
[Console]::Write($Meta2);
[Console]::Write("`n");
$Meta3=""
foreach ($el in $r.Meta3){
$Meta3+=$el
}
$Meta3=($Meta3 -split "[`r`n]") -join "`n"
$Meta3=($Meta3 -split "[`n]{2,}") -join "`n"
[Console]::Write("stdout:`n");
[Console]::Write($Meta3);
[Console]::Write("`n");
언급URL : https://stackoverflow.com/questions/24222088/capture-program-stdout-and-stderr-to-separate-variables
'programing' 카테고리의 다른 글
Oracle 11g dmp 가져오기.ORA-39000 / ORA-39143 오류 (0) | 2023.09.10 |
---|---|
복잡한 선택 CASE 식(하위 쿼리 포함)의 쿼리 시간을 줄이는 데 도움이 필요합니다. (0) | 2023.09.10 |
cs 플렉스박스에 래핑할 요소를 지정하는 방법? (0) | 2023.09.10 |
jQuery getJ올바른 JSON에 대한 SON 구문 오류 (0) | 2023.09.10 |
필터를 고려한 열의 중위수는 어떻게 구합니까? (0) | 2023.09.10 |