.bat 和 .cmd 在 ERRORLEVEL 上不同,谁决定 SET 的行为?

.bat and .cmd different on ERRORLEVEL, who determines SET's behavior?

我刚刚发现,SET 的行为对于 .bat.cmd 是不同的。我的实验表明,SET 的行为由启动批处理文件的扩展名(.bat 或 .cmd)决定,而不是由 SET 语句所在的文件扩展名决定。

这是 Windows NT CMD 批处理脚本引擎的一个模糊角落,Ben Hoffstein talks about it a bit。而我想知道,我的结论是否正确?或者,Microsoft docs 是否在某处正式讨论过这个问题?

我也想知道,有没有办法查看,甚至改变当前的模式?bat模式还是cmd模式?如果两者都不是,我不得不接受这样一个事实,即我们批处理脚本作者(尤其是将批处理编写为函数时)不能做出任何假设。

下面是我的实验

运行 来自 Windows 7 SP1。

showerr.bat

@echo off
setlocal EnableDelayedExpansion

call :SetErrorlevel 40
set var=1
echo Err=%ERRORLEVEL%

exit /b 0

REM ==== Functions below ====

:SetErrorlevel
exit /b %1

showerr.cmd

与 showerr.bat 相同。

开始-subcmd.bat

call showerr.cmd

开始-subbat.cmd

call showerr.bat

结果如下:

我建议 运行 .batset 保持 errorlevel 不变,但 .cmd 已“更正”为当 set 成功时将 errorlevel 设置为 0。

这并没有让我感到惊讶,尽管我之前从未测试过这个特定点...

以下信息来自我的个人经历。据我所知,这在任何地方都没有记录

通过call subFile.bat调用的“子程序”就是我所说的内部子程序。它继承 其父级的几个状态,如“echo on/off”等。现在,我知道它也继承了“BAT|CMD”模式。

当然,内部子例程与其父例程共享的最广为人知的值是环境变量。

通过 cmd /C subFile.bat 调用的子例程是 外部子例程 。当它启动时,它有一组新的几个状态的初始值,包括“BAT|CMD”模式。

查看此测试:

start-SubBat.cmd

call ShowErr.bat
cmd /C ShowErr.bat

输出:

Err=0
Err=40

start-SubCmd.bat

call ShowErr.cmd
cmd /C ShowErr.cmd

输出:

Err=40
Err=0

知道什么是“当前模式”的方法非常简单:首先通过 verify other 2>NUL 将错误级别设置为 1(这是 MS 建议的方法),然后执行 set var=1.如果新的 %errorlevel% 为 1,则处于 BAT 模式;如果为0,则表示您处于CMD模式。

为了完成这个主题,一个“子程序”通过它的名字执行,没有 call 也没有 cmd /C 命令(即只有 subFile.bat)被称为 overlay :在各个方面替代调用程序

Table 3.