[powershell] 언제 Write-Error vs. Throw를 사용해야합니까? 종료 대 비 종료 오류

PoshCode ( http://poshcode.org/3226) 에서 Get-WebFile 스크립트를 살펴보면 다음과 같은 이상한 충돌을 발견했습니다.

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

다음과 반대되는 이유는 무엇입니까?

$URL_Format_Error = [string]"..."
Throw $URL_Format_Error

또는 더 나은 :

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

내가 이해하는 것처럼 종료하지 않는 오류에는 Write-Error를 사용하고 오류는 종료하는 경우 Throw를 사용해야하므로 Write-Error 다음에 Return을 사용해서는 안됩니다. 차이가 있습니까?



답변

Write-Error중요하지 않은 오류를 사용자에게 알리려면 사용해야합니다. 기본적으로 콘솔에 오류 메시지가 빨간색 텍스트로 인쇄됩니다. 파이프 라인이나 루프가 계속되는 것을 막지는 않습니다. Throw반면에 종료 오류라고하는 것을 생성합니다. throw를 사용하면 파이프 라인 및 / 또는 전류 루프가 종료됩니다. 사실 trap또는 try/catch구조를 사용하여 종료 오류를 처리 하지 않으면 모든 실행이 종료됩니다.

당신이 설정 한 경우주의 할 점은있다 $ErrorActionPreference"Stop" 하고 사용 Write-Error이됩니다 종료 오류를 생성 .

당신이 링크 한 스크립트에서 우리는 이것을 발견합니다 :

if ($url.Contains("http")) {
       $request = [System.Net.HttpWebRequest]::Create($url)
}
else {
       $URL_Format_Error = [string]"Connection protocol not specified. Recommended action: Try again using protocol (for example 'http://" + $url + "') instead. Function aborting..."
       Write-Error $URL_Format_Error
    return
   }

해당 함수의 작성자가 해당 함수의 실행을 중지하고 화면에 오류 메시지를 표시하려고하지만 전체 스크립트의 실행을 중지하지 않으려는 것처럼 보입니다. 스크립트 작성자가 사용할 수는 throw있지만 try/catch함수를 호출 할 때 를 사용해야한다는 의미 입니다.

return함수, 스크립트 또는 스크립트 블록 일 수있는 현재 범위를 종료합니다. 이것은 코드로 가장 잘 설명됩니다.

# A foreach loop.
foreach ( $i in  (1..10) ) { Write-Host $i ; if ($i -eq 5) { return } }

# A for loop.
for ($i = 1; $i -le 10; $i++) { Write-Host $i ; if ($i -eq 5) { return } }

두 가지에 대한 출력 :

1
2
3
4
5

여기에 하나 개 잡았다 사용 return하여 ForEach-Object. 예상대로 처리를 중단하지 않습니다.

추가 정보:


답변

쓰기 오류 의 주요 차이점 cmdlet 및 던져 PowerShell의 키워드는 전자가 단순히이다 인쇄 받는 텍스트 표준 오류 스트림 (표준 오류) 후자는 실제로 동안 종료 된 실행 명령이나 함수의 처리, 처리를 오류 정보를 콘솔에 보내 PowerShell에 의해.

제공 한 예제에서 두 가지의 다른 동작을 관찰 할 수 있습니다.

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

이 예에서는 오류 메시지가 콘솔로 전송 된 후 스크립트 실행 return명시 적으로 중지 하기 위해 키워드가 추가 되었습니다. 반면 두 번째 예에서는return 종료가 암시 적으로 수행되므로 키워드가 필요하지 않습니다 throw.

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error


답변

중요 : 가지 유형의 종료 오류 가 있으며 현재 도움말 항목이 불행히도 충돌합니다 .

  • -terminating 오류, 특정 복구 할 수없는 상황에서 cmdlet에 의해 및 .NET 예외가 / PS 런타임 오류가 발생하는 식으로보고; 진술 종료 되고 기본적으로 스크립트 실행이 계속됩니다 .

  • 스크립트는 -terminating : (더 정확하게 오류 실행 영역-종료를 중 하나에 의해 트리거 등)Throw 또는 에러 동작 환경 변수 / 파라미터 값을 통해 오차 다른 유형 중 하나를 확대하여이 Stop.
    잡히지 않으면 현재 런 스페이스 (스레드)를 종료합니다. 즉, 현재 스크립트뿐만 아니라 해당하는 경우 모든 호출자도 종료합니다.

PowerShell의 오류 처리에 대한 포괄적 인 개요는 이 GitHub 설명서 문제를 참조하십시오. .

이 포스트의 나머지 부분은 비 종료진술 종결 에 중점을 둡니다. 오류 .


질문의 핵심에 중점을 둔 기존의 유용한 답변을 보완하려면 : 문장 종결 또는 비 종료 오류 보고 방법을 어떻게 선택 합니까 ?

Cmdlet 오류보고 에는 유용한 지침이 포함되어 있습니다. 실용 요약을 시도하겠습니다 .

비 종료 오류의 기본 개념 은 대규모 입력 세트의 “내결함성”처리를 허용 하는 것 입니다. 입력 객체 의 하위 세트 를 처리 하지 못하면 기본적으로 장기 실행 프로세스 를 전체적으로 중단해서는 안됩니다 . 자동 변수로 수집 된 오류 레코드를 통해보고 된대로 나중에 오류를 검사하고 실패한 개체 만 재 처리 할 수 있습니다 $Error.

  • cmdlet / 고급 기능인 경우 NON-TERMINATING 오류를 보고 하십시오.

    • 파이프 라인 입력 및 / 또는 배열 값 매개 변수를 통해 MULTIPLE 입력 객체를 받아들입니다.
    • 오류 SPECIFIC 입력 개체 발생 , AND
    • 이러한 오류는 원칙적으로 추가 입력 개체의 처리를 예방하지 않습니다 ( 상황 에 따라 입력 개체가 없거나 이전 입력 개체가 이미 성공적으로 처리되었을 수 있음).
      • 고급 기능에서 $PSCmdlet.WriteError()종료 Write-Error하지 않는 오류를보고하는 데 사용 합니다 ( 불행히도 호출자의 범위 에서 $?설정 되지 않음 – 이 GitHub 문제 참조 ).$False
      • 처리 종료되지 않는 오류 것은 : $?가장 최근의 명령이보고 여부를 알려줍니다 적어도 하나의 종료되지 않는 오류가 발생했습니다.
        • 따라서, $?존재 $False한다는 것은 (빈이 아닌) 서브셋을 입력 개체가 올바르게 아마도 전체 세트를 처리하지 않았다.
        • 기본 설정 변수 $ErrorActionPreference및 / 또는 공통 cmdlet 매개 변수 -ErrorAction는 오류 출력 동작 및 종료되지 않는 오류를 스크립트 종료 오류로 에스컬레이션해야하는지 여부에 따라 종료되지 않는 오류의 동작 (만)을 수정할 수 있습니다.
  • 다른 모든 경우에는 STATEMENT-TERMINATING 오류를 보고하십시오 .

    • 특히 SINGLE 또는 NO 입력 개체 만 허용하고 NO 또는 SINGLE 출력 개체를 출력하거나 매개 변수 입력 만 가져 오고 주어진 매개 변수 값이 의미있는 작업을 방해 하는 cmdlet / 고급 기능에서 오류가 발생하는 경우 .
      • 고급 기능에서는 $PSCmdlet.ThrowTerminatingError()명령문 종료 오류를 생성하기 위해 사용해야합니다 .
      • 반대로 Throw키워드 는 전체 스크립트 (기술적으로는 현재 스레드 ) 를 중단 시키는 스크립트 종료 오류를 생성합니다 .
      • 취급 성명 – 종료 오류를하십시오 try/catch핸들러 또는 trap문을 사용할 수 있습니다 (이 와 함께 사용할 수 비 종료 오류)하지만, 참고 심지어 기본적으로 -terminating 오류가 실행 스크립트의 나머지 부분을 방지하지 않습니다. 종료하지 않는 오류 와 마찬가지로 이전 명령문이 명령문 종료 오류를 트리거했는지 여부를 $?반영 $False합니다.

안타깝게도 모든 PowerShell 자체 핵심 cmdlet이 다음 규칙에 따라 작동하는 것은 아닙니다 .

  • 실패 할 가능성은 없지만 New-TemporaryFile(PSv5 +)는 파이프 라인 입력을 수락하지 않고 하나의 출력 개체 만 생성하더라도 실패하면 종료되지 않는 오류를보고합니다 . 그러나 최소한 PowerShell [Core] 7.0에서 수정되었습니다. 그러나이 GitHub를 참조하십시오. 문제 .

  • Resume-Job의 도움이 주장이 지원되지 않는 작업 유형을 (통과 등으로 생성 된 작업으로 Start-Job지원되지 않습니다, 때문에Resume-Job 워크 플로 작업 에만 적용 작업)을 전달하면 종료 오류가 발생하지만 PSv5.1에서는 사실이 아닙니다.


답변

Write-Error함수 소비자가 -ErrorAction SilentlyContinue(또는 -ea 0)로 오류 메시지를 표시하지 않도록합니다 . throw필요한 동안try{...} catch {..}

try … catch를 Write-Error다음 과 함께 사용하려면

try {
    SomeFunction -ErrorAction Stop
}
catch {
    DoSomething
}


답변

Andy Arismendi의 답변에 추가 :

쓰기 오류 가 프로세스를 종료 할지 여부 는 $ErrorActionPreference설정에 따라 다릅니다 .

사소한 스크립트의 경우 빠르게 실패 $ErrorActionPreference = "Stop"하도록 권장되는 설정 입니다.

“오류와 관련하여 PowerShell의 기본 동작은 오류가 계속됩니다 … VB6″다음 오류시 이력서 다시 시작 느낌 “-ish”

( http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/에서 )

그러나 Write-Error통화가 종료됩니다.

사용하려면 쓰기 오류 에 관계없이 다른 환경 설정의 비 종료 명령으로, 당신이 사용할 수있는 공통 매개 변수 -ErrorActionContinue:

 Write-Error "Error Message" -ErrorAction:Continue


답변

코드를 읽는 것이 정확하면 맞습니다. 종료 오류는을 사용해야 throw하며 .NET 유형을 처리하는 경우 .NET 예외 규칙을 따르는 것이 좋습니다.


답변