哪些cmd.exe内部命令在成功后将ERRORLEVEL清零?
哪些cmd.exe内部命令在成功后将ERRORLEVEL清零?
在Windows批处理脚本中处理错误的常见方法是使用类似于 if errorlevel 1 ...
或 if %errorlevel% neq 0 ...
的方式。通常情况下,人们希望错误处理代码能保留ERRORLEVEL。
我认为所有外部命令都会导致ERRORLEVEL设置为某个值,因此在执行外部命令之前,错误处理代码必须将ERRORLEVEL保存在环境变量中。
但是内部命令怎么办?问题是,某些内部命令在成功时将ERRORLEVEL清除为0,而有些则不会。我找不到任何说明哪些命令做什么的文档。
因此,问题是,哪些内部命令会在成功时将ERRORLEVEL清除为0?这不是关于返回的ERRORLEVEL代码的一般性问题,而是关于成功结果的严格问题。
有像什么是将ERRORLEVEL重置为零的最简单方法?和Windows批处理文件:.bat vs .cmd?的帖子提供了部分答案。但我从来没有看到过全面的列表。
注意:我对此已经好奇了很多年。因此,我最终决定进行一系列实验并得出最终答案。我发布了这个Q&A来分享我所发现的。
你对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。
这个答案是基于我在Windows 10下运行的实验结果得出的。我怀疑在使用cmd.exe的较早版本中可能存在差异,但这是有可能的。
还请注意,本答案不尝试记录内部命令在遇到错误时的ERRORLEVEL结果(除了对DEL和ERASE的少量描述)。
不仅有命令之间存在差异,而且单个命令可以根据它是从命令行运行的、拓展名为.bat
的批处理脚本内运行的,还是拓展名为.cmd
的批处理脚本内运行的,而表现出不同的行为。
以下一组命令永远不会在成功时将ERRORLEVEL清零,而是保持以前的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清零,不受上下文的影响:
- CD
- CHDIR
- COLOR
- COPY
- DATE
- DEL:即使DEL失败(除非没有任何文件参数运行),仍然会清除ERRORLEVEL。
- DIR
- ERASE:即使ERASE失败(除非没有任何文件参数运行),仍然会清除ERRORLEVEL。
- MD
- MKDIR
- MKLINK
- MOVE
- PUSHD
- REN
- RENAME
- SETLOCAL
- TIME
- TYPE
- VER
- VERIFY
- VOL
然后有这些命令,如果从命令行或拓展名为.bat
的脚本中发出,成功时不会将ERRORLEVEL清零,但如果从拓展名为.cmd
的脚本中发出,则会将ERRORLEVEL清零。有关更多信息,请参见https://stackoverflow.com/a/148991/1012053 和 https://groups.google.com/forum/#!msg/microsoft.public.win2000.cmdprompt.admin/XHeUq8oe2wk/LIEViGNmkK0J。
- ASSOC
- DPATH
- FTYPE
- PATH
- PROMPT
- SET
最后,有这些命令无法明确地归入任何先前的类别:
-
CALL:如果CALL了一个:routine或批处理脚本,则ERRORLEVEL仅由被CALL的脚本或:routine控制。但是,任何其他类型成功的对命令的CALL都将清除ERRORLEVEL为0,如果被CALL的命令没有另外设置它。
例如:call echo OK
。 -
EXIT:如果没有使用
/B
,则cmd.exe会终止会话,没有更多的ERRORLEVEL,只有cmd.exe返回代码。显然,EXIT /B 0
会将ERRORLEVEL清零,但是EXIT /B
没有值会保留上一个ERRORLEVEL。
除非我忽略了一个未记录的命令,否则我认为这就是所有内部命令的情况。