Windows 命令处理器cmd.exe 逐行处理批处理文件。这意味着它打开一个批处理文件,读取下一行,解析它,如果没有更多行要读取,它关闭批处理文件。然后它在解析的行上执行命令。见How does the Windows Command Interpreter (CMD.EXE) parse scripts?
如果此处存在严重语法,Windows 命令处理器将退出批处理文件的处理。此处使用此错误条件处理。
使用以下行创建一个批处理文件:
@echo off
goto
echo Third line!
打开command prompt 并通过键入其完整的限定文件名来运行此批处理文件,即驱动器+路径+名称+扩展名括在双引号中。
由于第二行缺少批处理标签,cmd.exe 输出以下错误消息。
没有为 GOTO 命令指定批处理标签。
cmd.exe 不再执行第三行,因为在执行第二个命令行后退出批处理文件处理,因为这个严重的语法错误,cmd.exe 不清楚在哪里继续批处理文件处理。
现在让我们看看命令行:
goto 2>nul & del /Q "%APP_PATH%"
这是一个命令行,在一行中有两个命令,如我在Single line with multiple commands using Windows batch file 上的回答中详细描述的那样。
带有缺少批处理标签的第一个命令goto 导致退出批处理文件处理。在这种情况下,cmd.exe 输出的错误消息使用2>nul 重定向到设备 NUL 以抑制它。但是第二个命令del /Q "%APP_PATH%" 已经扩展了环境变量%APP_PATH% 已经在命令队列中。因此,接下来会执行此命令。
然后cmd.exe 甚至不再尝试打开批处理文件以读取第三行,因为无效的goto 命令导致退出批处理文件处理,在这种情况下,如果%APP_PATH% 引用该批处理文件甚至不再存在批处理文件的名称。
顺便说一句:APP_PATH 很奇怪,因为带有完整路径的 文件名 的环境变量名称具有误导性。
这是一个更好的例子:
首先创建一个名为 Test1.cmd 的批处理文件,其中包含以下几行:
@echo off
echo %~nx0 is calling Test2.cmd.
call "%~dp0Test2.cmd"
echo %~nx0 is processed further.
创建第二个名为 Test2.cmd 的批处理文件,其中包含以下几行:
@echo off
set "BatchFile=%~f0"
echo %~nx0 is deleting itself now.
goto 2>nul & del /A /F "%BatchFile%"
然后从命令提示符窗口Test1.cmd 中运行。输出是:
Test1.cmd is calling Test2.cmd.
Test2.cmd is deleting itself now.
Test1.cmd is processed further.
cmd.exe处理Test2.cmd可以看出Test2.cmd删除了自己,没有显示任何错误信息。但Test1.cmd 的处理在Test2.cmd 自行删除后继续进行。
/Q 选项在删除单个文件时并不是真正需要的,并且在运行命令时该文件肯定存在。 /A 选项对于删除批处理文件很有用,即使它的隐藏属性设置为,否则 del 不会删除它。即使设置了只读属性,/F 选项对于删除批处理文件也很有用。
另一种命令方法是使用批处理文件中的最后一个命令行,它应该删除自己的命令行:
del /A /F "%~f0" & exit
但它有一个缺点,因为它可以在使用以下行创建 Test2.cmd 时看到:
@echo off
echo %~nx0 is deleting itself now.
del /A /F "%~f0" & exit
在命令提示符窗口中运行 Test1.cmd。批处理文件Test2.cmd 会自行删除,但命令exit 会导致退出cmd.exe 打开命令提示符窗口并处理两个批处理文件。因此,Test1.cmd 不会被进一步处理,控制台窗口会立即关闭。
在命令exit 之后附加选项/B 将导致不退出cmd.exe,但cmd.exe 将输出两条错误消息,因为找不到Test2.cmd。
因此,goto 2>nul & del /A /F "%~f0" 的使用是自删除批处理文件的最佳实践示例。
顺便说一句:顺序或两个命令很重要。使用del /A /F "%~f0" & goto 2>nul 会导致cmd.exe 输出错误消息,因为在这种情况下它会尝试再次打开已删除的批处理文件。