哪些cmd.exe内部命令在成功后将ERRORLEVEL清零?

15 浏览
0 Comments

哪些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来分享我所发现的。

admin 更改状态以发布 2023年5月25日
0
0 Comments

你对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。
0
0 Comments

这个答案是基于我在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/1012053https://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。

除非我忽略了一个未记录的命令,否则我认为这就是所有内部命令的情况。

0