打印exit命令的帮助信息,执行命令【exit /?】。
- C:\Users\Administrator>exit /?
- 退出 CMD.EXE 程序(命令解释器)或当前批处理脚本。
-
- EXIT [/B] [exitCode]
-
- /B 指定要退出当前批处理脚本而不是 CMD.EXE。如果从一个
- 批处理脚本外执行,则会退出 CMD.EXE
-
- exitCode 指定一个数字号码。如果指定了 /B,将 ERRORLEVEL
- 设成那个数字。如果退出 CMD.EXE,则用那个数字设置
- 过程退出代码。
打印goto命令的帮助信息,执行命令【goto /?】。
- C:\Users\Administrator>goto /?
- 将 cmd.exe 定向到批处理程序中带标签的行。
-
- GOTO label
-
- label 指定批处理程序中用作标签的文字字符串。
-
- 标签必须单独一行,并且以冒号打头。
-
- 如果命令扩展被启用,GOTO 会如下改变:
-
- GOTO 命令现在接受目标标签 :EOF,这个标签将控制转移到当前
- 批脚本文件的结尾。不定义就退出批脚本文件,这是一个容易的
- 办法。有关能使该功能有用的 CALL 命令的扩展描述,请键入
- CALL /?。
从上面的帮助信息,我们也可以了解到,如果不考虑exit指令的exitcode,那么一共有3种退出cmd窗口或者批处理脚本程序(子程序)的方法,分别是【exit】、【exit /b】、【goto :eof】。
但是,上面3种方法对应的3条指令,在各个位置(情况)执行的结果却大有不同。
下面这张思维导图,尽可能列举了各种有几率存在差异的情况。

看上去一共有14种情况,但其实有一些情况在测试过程中表现出明显的同一性,可以划等号(绿色箭头连接),而叠加环境的情况在bat文件中完全无影响。详见后续的7.1.1-7.1.3。
在此直接给出简化的测试思维导图,直接用【双击执行bat】代替用【cmd窗口执行bat】,直接用【call调用脚本内部子程序】代替【call外部调用】,直接用【不叠加环境】执行脚本。

在【D:\D-desktop】目录下新建一个main.bat文件,代码如下
- @echo off
- chcp 65001
- echo "主程序开始执行"
- echo "下一条指令调用demo"
- call D:\D-desktop\demo.bat
- pause
再在同一目录新建一个demo.bat文件,代码如下
- @echo off
- echo "子程序开始执行"
- echo "下一条执行exit"
- exit
- echo "子程序的exit执行完了"
直接双击执行main.bat,cmd窗口打开的瞬间又闪退。
而在手动打开的cmd窗口中执行main,这个手动打开的cmd窗口也闪退。

在【D:\D-desktop】目录下新建一个main.bat文件,代码如下。
- @echo off
- chcp 65001
- echo "主程序开始执行"
- echo "下一条指令调用demo"
- call D:\D-desktop\demo.bat
- pause
再在同一目录新建一个demo.bat文件,代码如下。
- @echo off
- echo "子程序开始执行"
- echo "下一条执行exit /b"
- exit /b
- echo "子程序的exit /b执行完了"
直接双击执行main.bat,cmd窗口打开后,能正常输出,值得注意的是【echo "子程序的exit /b执行完了"】并没有输出,因为执行【exit /b】后就退出demo.bat程序了。

而在手动打开的cmd窗口中执行main,这个手动打开的cmd窗口也输出了和上面【双击执行】一样的结果。
在【D:\D-desktop】目录下新建一个main.bat文件,代码如下。
- @echo off
- chcp 65001
- echo "主程序开始执行"
- echo "下一条指令调用demo"
- call D:\D-desktop\demo.bat
- pause
再在同一目录新建一个demo.bat文件,代码如下。
- @echo off
- echo "子程序开始执行"
- echo "下一条执行goto :eof"
- goto :eof
- echo "子程序的goto :eof执行完了"
直接双击执行main.bat,cmd窗口打开后,能正常输出,值得注意的是【echo "子程序的goto :eof执行完了"】并没有输出,因为执行【goto :eof】后就退出demo.bat程序了。

而在手动打开的cmd窗口中执行main,这个手动打开的cmd窗口也输出了和上面【双击执行】一样的结果。


(1)先测试【call调用脚本内子程序】的情况~
在【D:\D-desktop】目录下新建一个main.bat文件,代码如下。
- @echo off
- chcp 65001
- echo "主程序开始执行"
- echo "下一条指令调用demo"
- call:demo
- pause
-
- :demo
- echo "子程序开始执行"
- echo "下一条执行goto :eof"
- goto :eof
- echo "子程序的goto :eof执行完了"
直接双击执行main.bat,cmd窗口打开后,能正常输出,值得注意的是【echo "子程序的goto :eof执行完了"】并没有输出,因为执行【goto :eof】后就退出demo.bat程序了。

(2)接着测试【call调用外部脚本】的情况~
在【D:\D-desktop】目录下新建一个main.bat文件,代码如下。
- @echo off
- chcp 65001
- echo "主程序开始执行"
- echo "下一条指令调用demo"
- call D:\D-desktop\demo.bat
- pause
再在同一目录新建一个demo.bat文件,代码如下。
- @echo off
- echo "子程序开始执行"
- echo "下一条执行goto :eof"
- goto :eof
- echo "子程序的goto :eof执行完了"
直接双击执行main.bat,cmd窗口打开后,能正常输出,值得注意的是【echo "子程序的goto :eof执行完了"】并没有输出,因为执行【goto :eof】后就退出demo.bat程序了。
在前面直接给出简要的结论。
【exit】。不管是在主程序中执行还是子程序(批处理脚本)中执行,不管是在程序的第几层执行,都会直接导致cmd窗口的退出。
【goto :eof】。如果在脚本主程序中执行,就会立即退出脚本;如果在主脚本中调用子脚本时执行,会退出子脚本而继续向下执行上一层的脚本程序;如果在脚本内的子程序中执行,就会退出子程序而继续执行主程序。注意它不能用来退出环境,这一点只有exit和exit /b支持。
【exit /b】。除了可以添加exitcode参数,还有必须在命令扩展打开的时候使用,以及在退出环境方面和exit效果近似,其他与【goto :eof】可以说完全相同。
如果你是在cmd原生窗口中执行exit命令,意思就是说没有进入某种命令的环境,比如python环境、diskpart环境、命令扩展环境、扩展变量或延迟变量环境,那么cmd窗口会直接被关闭。



假如我已经进入到了python环境,然后想返回到原生cmd环境中,直接执行exit()命令即可。

如果执行exit,会出错的。

对于命令【exit /b】和命令【goto :eof】,出错更厉害!

假如你在cmd窗口中执行diskpart命令进入对应环境中, 而后程序会自动弹出一个关于diskpart.exe的窗口。
错误的返回原生cmd窗口的方式是单击diskpart.exe窗口右上角的“叉叉”,由于这样会导致原生Cmd窗口无法正常使用,后续只能重开。

正确的返回cmd原生环境的方式应该是在diskpart.exe窗口中执行exit命令。


对于命令【exit /b】,也是能用来退出diskpart环境的。

命令【goto :eof】却无法退出diskpart环境。


当我们在原生CMD窗口中执行命令【cmd /e:on】时,标题后面就新加了一串命令文字,这其实就属于叠加了一层cmd环境(命令扩展环境)。

我们可以用exit命令来一层一层地退出cmd环境。

进入扩展变量环境后,执行命令【goto :eof】没反应,说明不能用来退出环境。

进入扩展变量环境后,执行命令【exit /b】有反应(见蓝色圈圈),说明可用来退出环境。

在cmd原生窗口中执行命令【cmd /v:on】(或命令【cmd /v)来打开延迟变量环境,同样标题栏也会多一串命令字符。

如果要退出这层环境,也可以用exit退出。

进入扩展变量环境后,执行命令【goto :eof】没反应,说明不能用来退出环境。

进入扩展变量环境后,执行命令【exit /b】有反应(见蓝色圈圈),说明可用来退出环境。

其他的cmd环境,可以在cmd /?中查看,退出的方法都是执行命令【exit】,我就不再赘述了。
(1)直接退出cmd窗口的情况
当你在脚本文件中,没有启动或打开任何的环境,那么执行exit命令的瞬间就会直接关闭cmd窗口。
如下代码,复制进一个bat文件后双击执行,发现cmd窗口闪退。
- @echo off
- echo main1.bat start to execute!
- call :end
- pause
- :end
- echo subprogram is executeing!
- exit
显然,是在调用子程序时,执行了子程序的【exit】才退出cmd窗口的,没来得及执行主程序的Pause命令。
(2)cmd系列命令不建议在脚本文件使用
假如我略加修改一下上面(1)的代码,添加一层cmd环境(扩展变量环境),就不会闪退了。
原因倒并不是因为叠加了一层环境后,执行exit命令是退出环境;原因在于叠加了一层环境后,所有的命令都失效了,包括exit命令。
- @echo off
- echo main1.bat start to execute!
- cmd /v
- call :end
- pause
- :end
- echo subprogram is executeing!
- exit

之所以在标题中说是情况一样,是因为在叠加环境时,下面的指令也会失效。
而如果不叠加环境,一旦执行exit命令,cmd窗口也会闪退。
测试代码如下。
main.bat的代码。
- @echo off
- chcp 65001
- echo "主程序开始执行"
- echo "下一条指令调用demo"
- cmd /v:on
- call D:\D-desktop\demo.bat
- echo "在子程序中执行exit之后,主程序call下面的代码都不执行"
- pause
demo.bat的代码。
- @echo off
- chcp 65001
- echo "在脚本文件中,一旦进入了cmd环境,就不能再echo任何内容"
- echo "所以子程序的所有输出都被忽略了"
- echo "子程序开始执行"
- echo "下一条执行exit"
- exit
- echo "子程序的exit执行完了"
- echo "对于exit后面的代码,显然不执行了"
双击执行,结果如下 。

我们显然也可以看到,只要执行了【cmd /v:on】,下面的代码都失效了。
而比较惊奇的另一点,虽然主程序最后一行的pause命令失效,但是执行bat脚本文件时也没出现闪退。
而如果把进入环境的指令去掉,就又会出现闪退问题,估计是因为exit命令又生效了。
所以,你们知道为啥我在7.3.1的某标题说不要在批处理脚本中执行类似【cmd /e:on】、【cmd /v:on】的命令了吧?因为cmd开发人员可能压根就没想着我们用户在这里用。
因为有专门的批处理脚本命令【setlocal ENABLEEXTENSIONS】和【setlocal ENABLEDELAYEDEXPANSION】我们却不用,四不四傻?
另外,根据我测试这么久的经验,发现只要使用call命令调用,不管是调用本脚本内的子程序还是调用外部脚本,结果都一样,因此后面只进行其中一种测试。
在cmd窗口中执行bat脚本程序,情况和上面的7.3完全一样。
也是执行命令【cmd /v:on】后,下面的指令全部失效(包括exit);如果没进入cmd环境时,执行exit会直接关闭cmd窗口。
如下所示,如果代码最后一行有exit,并且exit之前没有进入环境,就直接退出当前cmd窗口。
- @echo off
- chcp 65001
- echo "main1.bat开始执行"
- echo "下一条执行exit命令"
- exit
如下所示,在Exit前加一行环境激活命令,那么exit就不会生效,但缺点也很明显,其他该生效的也失效了。
- @echo off
- chcp 65001
- echo "main1.bat开始执行"
- cmd /v:on
- echo "下一条执行exit命令"
- exit
