2016-01-23 49 views
21

在Windows批處理腳本中處理錯誤的常用方法是使用諸如
if errorlevel 1 ...if %errorlevel% neq 0 ...之類的東西。經常有人希望錯誤處理代碼保存ERRORLEVEL。成功後,哪些cmd.exe內部命令將ERRORLEVEL清除爲0?

我相信所有外部命令總是會導致ERRORLEVEL被設置爲某個值,因此錯誤處理代碼必須在執行外部命令之前將環境變量中的ERRORLEVEL保留。

但是內部命令呢?問題是,一些內部命令在成功時將ERRORLEVEL清除爲0,有些則不然。我找不到任何文件指定哪些命令做什麼。

所以問題是,哪些內部命令在成功時將ERRORLEVEL清除爲0?這是不是關於返回的ERRORLEVEL代碼的一般問題,但嚴格關於成功結果。

有類似What is the easiest way to reset ERRORLEVEL to zero?Windows batch files: .bat vs .cmd?的帖子給出部分答案。但我從來沒有見過一個全面的名單。

注:我一直好奇這個多年。所以我最終決定進行一系列實驗並提出一個明確的答案。我發佈這個Q & A分享我發現的東西。

+2

請參閱:http://stackoverflow.com/questions/34987885/what-are-the-errorlevel-values-set-by-internal- cmd-exe -keys/ – Aacini

回答

21

這個答案是基於我在Windows 10下運行的實驗。我懷疑與使用cmd.exe的早期Windows版本存在差異,但它是可能的。

還要注意 - 這個答案並不試圖記錄下ERRORLEVEL結果當內部命令遇到錯誤(除了關於DEL一丁點兒和擦除)

不僅有命令之間的區別,但單個命令的行爲可能會有所不同,具體取決於它是從命令行運行的,還是在擴展名爲.bat的批處理腳本中運行,或者在擴展名爲.cmd的批處理腳本中運行。

以下命令集從未在成功清除ERRORLEVEL爲0,而不管上下文,而是保留之前ERRORLEVEL:

  • BREAK
  • CLS
  • ECHO
  • ENDLOCAL
  • FOR:很明顯,DO子句中的命令可能會設置ERRORLEVEL,但至少有一次迭代的成功FOR不會將ERRORLEVEL設置爲0。
  • GOTO
  • IF:顯然,由IF執行的命令可能會設置ERRORLEVEL,但成功的IF本身並不會將ERRORLEVEL設置爲0。
  • KEYS
  • PAUSE
  • POPD
  • RD
  • REM
  • RMDIR
  • SHIFT
  • START
  • TITLE

下一組命令的總是在成功清除ERRORLEVEL爲0,而不管上下文:

  • CD
  • CHDIR
  • COLOR
  • COPY
  • DATE
  • DEL:總是清除ERRORLEVEL,即使DEL失敗(運行時沒有任何文件參數除外)
  • DIR
  • ERASE:即使ERASE失敗,始終清除ERRORLEVEL。 (運行時沒有任何文件參數除外)
  • MD
  • MKDIR
  • MKLINK
  • MOVE
  • PUSHD
  • REN
  • RENAME
  • SETLOCAL
  • TIME
  • TYPE
  • VER
  • 校驗
  • VOL

再就是這些命令,如果命令行或用.bat擴展名的腳本中發佈了做成功時不明確ERRORLEVEL,但做清除ERRORLEVEL爲0;如果發行從具有.cmd擴展名的腳本中刪除。有關更多信息,請參閱https://stackoverflow.com/a/148991/1012053https://groups.google.com/forum/#!msg/microsoft.public.win2000.cmdprompt.admin/XHeUq8oe2wk/LIEViGNmkK0J

  • ASSOC
  • DPATH
  • FTYPE
  • PATH
  • PROMPT
  • SET

最後,有這些命令不完全適合任何事先的類別:

  • 調用:如果a:例程或批處理腳本被調用,則ERRORLEVEL由CALLed腳本或:例程獨佔控制。但是,如果CALLed命令不另外設置它,則任何其他類型的成功CALL命令都將清除ERRORLEVEL爲0。
    例如:call echo OK

  • EXIT:如果在沒有/B的情況下使用,則cmd.exe會話將終止並且不再有ERRORLEVEL,只是cmd.exe返回碼。很顯然EXIT /B 0將ERRORLEVEL清除爲0,但沒有值的EXIT /B保留了先前的ERRORLEVEL。

我相信,所有內部命令的帳戶,除非有一個我沒有記錄的未公開的命令。

+1

'KEYS' is missing ... :)(沒有清除錯誤級別) – npocmaka

+0

@npocmaka - 謝謝,我已將它添加到列表中 – dbenham

+0

...只是一個附註:'rem'在Windows NT 4.0上重置「ErrorLevel」爲零;據我記憶,這是從Windows XP已經修復... – aschipfl

4

CALL命令的描述不完整:

CALL:清除ERRORLEVEL如果被叫命令不以其他方式設置。例如:call echo OK

檢查這個小例子:

@echo off 

call :setTwo 
echo Set two: %errorlevel% 

call :preserve 
echo Preserve: %errorlevel% 

call echo Reset 
echo Reset: %errorlevel% 

call :subNotExists 2> NUL 
echo Sub not exist: %errorlevel% 

goto :EOF 

:setTwo 
exit /B 2 

:preserve 
echo Preserve 
exit /B 

輸出:

Set two: 2 
Preserve 
Preserve: 2 
Reset 
Reset: 0 
Sub not exist: 1 

CALL說明應該是這樣的:

  • CALL:清除ERRORLEVEL如果被叫命令執行沒有其他設置。例如:call echo OK,但是如果被調用的命令是一個子例程,它將保留先前的ERRORLEVEL。如果被調用子程序不存在,它將ERRORLEVEL設置爲1.
+1

我的答案並不矛盾這個答案,因爲這個問題只是關於***成功***內部命令的結果。您選擇了有選擇地添加有關不成功的命令結果的信息。這是有用的信息,但不回答這個問題。我想過要問一個關於內部命令錯誤處理的普遍問題,但是認爲它太寬泛而且很難回答。 (雖然我希望有一天能看到一篇全面的論文!)我也考慮過在我的答案中選擇性地包含錯誤結果,但選擇保持清潔 - 嚴格限制成功結果。 – dbenham

+1

檢查 - 我確實讓我的一些錯誤結果潛入到我的答案中,並描述了DEL和ERASE ;-) – dbenham

+0

那麼,除了「ERRORLEVEL = 1 when subroutine does not exist」時,「如果被調用的命令是一個子程序保留了先前的ERRORLEVEL「部分是指_successful_結果。無論如何,我真的認爲這個話題應該討論一般由內部命令設定的值。我認爲這部分不會太寬泛,如果你只是提到某些命令將ERRORLEVEL設置爲1「在錯誤條件下」,只是對這些條件的簡要描述。 IMO ERRORLEVEL = not zero part不能從ERRORLEVEL = 0部分的描述中排除。 – Aacini