PowerShell的異常處理辦法
在使用 PowerShell 的過程中,發現它的異常處理並不像想象中的那麼直觀,所以在這裡總結一下。
Terminating Errors
透過 ThrowTerminatingError 觸發的錯誤稱為 Terminating Errors。本質上它是建立了一個異常,所以我們可以使用 catch 語句來捕獲 Terminating Errors。因此 Terminating Errors 的另外一個名字叫 Exceptions。預設情況下,Terminating Errors 不影響後面命令的執行!
把下面的程式碼儲存到檔案 exception.ps1 中:
# 下面的命令不存在 Get-TerminatingError Write-Host 'hello world'
然後執行指令碼 exception.ps1:
注意最後輸出的 "hello world",雖然執行過程中出現了錯誤,但是錯誤後面的程式碼依然被執行了。
Terminating Errors 的特點是預設情況下你可以透過 catch 語句捕獲它,從而控制程式碼的執行流。
把下面的程式碼儲存到檔案 exception.ps1 中:
Try{ # 下面的命令不存在 Get-TerminatingError } Catch{ Write-Host 'got you' exit 1 } Write-Host 'hello world'
然後執行指令碼 exception.ps1:
這樣就好多了,我們預測了程式碼中可能產生的問題,並且在發生了錯誤的情況下果斷的結束了指令碼的執行。
雖然 Terminating Errors 不能中斷指令碼的執行,但是卻可以中斷 pipeline 的執行。從 Terminating Errors 的文件中我們可以看到,其內部丟擲了 PipelineStoppedException 異常,並且 PowerShell 內部處理了這個異常。所以正在執行的 pipeline 會被中斷掉,然後繼續執行後面的其它程式碼。
Non-Terminating Errors
透過 Write-Error 觸發的錯誤稱為 Non-Terminating Errors。本質上它只是把錯誤資訊寫入了輸出流中而沒有產生異常,所以預設情況下 catch 語句無法捕獲 Non-Terminating Errors。預設情況下,Non-Terminating Errors 不影響後面命令的執行!
把下面的程式碼儲存到檔案 exception.ps1 中:
# C:xxx 不存在 Copy-Item C:xxx Write-Host 'hello world'
然後執行指令碼 exception.ps1:
注意最後輸出的 "hello world",雖然執行過程中出現了錯誤,但是錯誤後面的程式碼依然被執行了。
Non-Terminating Errors 的特點是預設情況下 catch 語句無法捕獲它!
把下面的程式碼儲存到檔案 exception.ps1 中:
Try{ # C:xxx 不存在 Copy-Item C:xxx } Catch{ Write-Host 'got you' exit 1 } Write-Host 'hello world'
然後執行指令碼 exception.ps1,結果和上面是一樣的,錯誤後面的程式碼依然會被執行。
ErrorAction 選項的秘密
Non-Terminating Errors 預設只是透過 Write-Error 把錯誤資訊寫入了輸出流中而沒有產生異常,所以 catch 語句無法捕獲 Non-Terminating Errors。但是我們卻可以透過 -ErrorAction 選項改變 WriteError 的預設行為。
ErrorAction 選項主要用來改變命令的 non-terminating errors 的行為(它不會對 Terminating Errors 產生影響)!
ErrorAction 選項的工作原理為:用指定的引數覆蓋當前命令的 $ErrorActionPreference 變數。預設情況下 $ErrorActionPreference 變數的值為 Continue。
可以為 -ErrorAction 選項指定下面的引數:
-ErrorAction[:{Continue | Ignore | Inquire | SilentlyContinue | Stop | Suspend }]
它們表示的含義如下:
Continue 顯示錯誤資訊並繼續執行後面的命令,這是預設值。
Ignore 這個值是在 PowerShell 3.0 引入的。它不顯示錯誤資訊並繼續執行後面的命令。與 SilentlyContinue 不同的是,它也不會把錯誤資訊新增到 $Error 變數中。
Inquire 顯示錯誤資訊並彈框與使用者互動。
SilentlyContinue 不顯示錯誤資訊並繼續執行後面的命令。
Stop 顯示錯誤資訊並且退出指令碼的執行。
Suspend 這個值只適用於 workflow。當 terminating error 發生時執行會暫停下來,然後決定是否恢復執行。
這裡我們重點關注使用比較多的 stop, 它會讓 Write-Error 等原本產生 non-terminating error 的命令產生 terminating error!所以我們就可以用 catch 語句來捕獲異常了。把下面的程式碼儲存到檔案 exception.ps1 中:
Try{ # C:xxx 不存在 Copy-Item C:xxx -ErrorAction Stop } Catch{ Write-Host 'got you' exit 1 } Write-Host 'hello world'
注意我們為 Copy-Item 命令新增了 -ErrorAction Stop 選項,然後執行指令碼 exception.ps1:
哈哈,這次捕獲到異常了,並且最後也沒有輸出 "hello world"。
如果需要給每個命令都新增 -ErrorAction 選項可不是什麼好玩的事情,好在我們可以在指令碼中設定 $ErrorActionPreference 變數來完成同樣的功能:
$ErrorActionPreference = 'Stop'
這樣在當前的指令碼中,所有原本的 non-terminating error 都會變成 terminating error。
Try/Catch/Finally
在異常處理中不介紹 Try/Catch/Finally 語句是不完整的。Catch 語句用來捕獲 Try 塊中產生的異常,當然我們可以指定只捕獲那些我們感興趣的異常。
Finally 塊也是非常重要的,它能保證一些必要的邏輯被執行,比如釋放資料庫連線。下面的 demo 演示瞭如何在指令碼中設定 $ErrorActionPreference 變數:
$eap = $ErrorActionPreference Try{ $ErrorActionPreference = 'Stop' # do something } Catch{ Write-Host "error !" Exit 1 } Finally{ $ErrorActionPreference = $eap }
在 Finally 塊中把 $ErrorActionPreference 變數還原,保證我們自己設定的 $ErrorActionPreference 變數隻影響 Try/Catch 塊中的語句。
$PSItem 變數
$PSItem 是一個 ErrorRecord 型別的變數,它會儲存異常的詳細資訊。在捕獲到異常時,我們可以把異常相關的資訊輸出或儲存到日誌中:
$eap = $ErrorActionPreference Try{ $ErrorActionPreference = 'Stop' # 下面的命令不存在 Get-TerminatingError } Catch{ # 比較簡潔的資訊 Write-Output $PSItem.ToString() } Finally{ $ErrorActionPreference = $eap }
$PSItem.ToString() 中只有錯誤的描述,看起來會比較簡潔。執行上面的指令碼:
紅框中的資訊就是 $PSItem.ToString() 提供的。
僅有錯誤資訊並不總是能夠很好的幫助調查問題的根源,如果有出錯的行號和異常堆疊會好很多:
$eap = $ErrorActionPreference Try{ $ErrorActionPreference = 'Stop' # 下面的命令不存在 Get-TerminatingError } Catch{ # 包含堆疊的資訊 Write-Output $PSItem } Finally{ $ErrorActionPreference = $eap }
這次我們直接輸出了 $PSItem,執行上面的程式碼會得到下面的輸出:
這下好多了,有了出錯的行號和呼叫堆疊就可以很容易的看到出錯的原因。
結論
作為一門指令碼語言,PowerShell 對異常的支援還是非常強大的。不過像 Terminating Errors 和 Non-Terminating Errors 這樣的特性也會給我們帶來不少的困擾。希望本文介紹的內容可以幫助大家更好的理解 PowerShell 中異常相關的概念。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2459/viewspace-2800317/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 異常的處理
- 異常-throws的方式處理異常
- 異常篇——異常處理
- 異常處理
- JSP 異常處理如何處理?JS
- React 異常處理React
- JS異常處理JS
- oracle異常處理Oracle
- Python——異常處理Python
- Python異常處理Python
- ThinkPHP 異常處理PHP
- JavaScript 異常處理JavaScript
- JAVA 異常處理Java
- golang - 異常處理Golang
- 異常處理2
- 異常處理1
- Java 異常處理Java
- Abp 異常處理
- JAVA異常處理Java
- 08、異常處理
- SpringMVC異常處理SpringMVC
- 異常處理機制(二)之異常處理與捕獲
- 異常-try...catch的方式處理異常1
- 異常-try...catch的方式處理異常2
- Java 異常表與異常處理原理Java
- restframework 異常處理及自定義異常RESTFramework
- springboot下新增全域性異常處理和自定義異常處理Spring Boot
- NodeJS之異常處理NodeJS
- JAVA_異常處理Java
- React Native 異常處理React Native
- Spring Boot 異常處理Spring Boot
- PHP 核心 - 異常處理PHP
- GRpc異常處理FilterRPCFilter
- python異常捕捉處理Python
- 14. 異常處理
- 異常處理機制
- 異常處理方式throws
- 處理多個異常