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


145

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을 사용해서는 안됩니다. 차이가 있습니까?


4
무슨 소리 야? Write_error가 스크립트를 계속 허용하면 Write-Error 후에 return 문을 갖는 것이 매우 이해할 수 있습니다. 오류가 기록되었으며 처음에는 함수를 호출 한 코드로 돌아갑니다. Throw는 오류를 종료하기위한 것이므로 자동으로 종료되므로 throw 선언의 return 문이 쓸모가 없습니다.
Gisli

1
@Gisli : 그것은 유의해야 return않습니다 하지 에서 호출자에게 반환 process(고급) 함수의 블록; 대신 파이프 라인 의 다음 입력 개체 로 진행됩니다 . 실제로 이것은 종료되지 않은 오류를 생성하는 일반적인 시나리오입니다. 추가 입력 개체를 계속 처리 할 수있는 경우.
mklement0

1
스크립트 종료 오류 를 Throw생성 합니다 .이 오류는 예를 들어 또는 에 의해 트리거 된 명령문 종료 오류 와 다릅니다 . Get-Item -NoSuchParameter1 / 0
mklement0

답변:


188

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. 예상대로 처리를 중단하지 않습니다.

추가 정보:


자, Throw는 모든 것을 멈추고 Write-Error + return은 현재 기능 만 멈 춥니 다.
Bill Barry

@ BillBarry 나는에 대한 설명으로 답변을 약간 업데이트했습니다 return.
Andy Arismendi

OS에 적절한 오류 코드가 반환되도록 Write-Error 다음에 exit (1)를 사용하는 것은 어떻습니까? 그게 적절한가요?
pabrams

19

쓰기 오류 의 주요 차이점 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

2
$ ErrorActionPreference = "Stop"이 있으면 Write-Error도 프로세스를 종료합니다.
Michael Freidgeim

4
좋은 정보지만, PowerShell에서의 에러 스트림 인 반면 유사 받는 텍스트 기반의 다른 셸의 표준 오류 스트림 모두 PowerShell을 스트림처럼, 그것은 포함 객체 , 즉 [System.Management.Automation.ErrorRecord]자동 수집 기본적으로있는 경우, $Error수집 ( $Error[0]가장 최근의 오류가 있습니다). stringWrite-Error 과 함께 사용하더라도 해당 문자열은 인스턴스에 래핑됩니다 . [System.Management.Automation.ErrorRecord]
mklement0

16

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

  • -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에서는 사실이 아닙니다.


8

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

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

try {
    SomeFunction -ErrorAction Stop
}
catch {
    DoSomething
}

오류 메시지를 표시하지 않으려면 왜 Write-Error를 호출해야합니까?
Michael Freidgeim

8

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

0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.