我试图理解代码中GOTO :EOF
会返回到哪里?
以下是代码:
SET count=1
FOR /f "tokens=*" %%G IN (somefile.txt) DO (call :subroutine "%%G")
GOTO :EOF
:subroutine
echo %count%:%1
set /a count+=1
GOTO :EOF
我试图理解代码中GOTO :EOF
会返回到哪里?
以下是代码:
SET count=1
FOR /f "tokens=*" %%G IN (somefile.txt) DO (call :subroutine "%%G")
GOTO :EOF
:subroutine
echo %count%:%1
set /a count+=1
GOTO :EOF
:EOF
是一个预定义标签,如Microsoft在GOTO命令的文档中所解释的。在命令提示符窗口中运行goto /?
的帮助输出也解释了这个特殊的标签用于文件结束。但是默认情况下,只有启用命令扩展时才支持此预定义标签。call /?
的帮助输出以及CALL命令的文档都解释了goto :EOF
应该用于退出由call :Label
调用的子例程。call
命令调用的另一个批处理文件。如果子例程位于批处理文件的末尾,则真正的文件结束标记标志着子例程的结束。goto :EOF
还是exit /B
都可以在任何地方使用,以退出子例程或退出当前批处理文件处理。goto :EOF
用于在完成循环后,退出批处理文件处理而不会意外地落入子例程代码中。goto :EOF
用于退出子例程并继续处理第二行中的FOR循环。它不会退出批处理文件的处理,只会退出子例程的处理。
注意1:goto EOF
没有冒号的要求是批处理文件中确实存在以:EOF
开头的行,即标签EOF
必须存在于文件中。即使批处理文件中有一个以:EOF
开头的行,goto :EOF
始终会启用命令扩展来退出子例程/批处理处理。
注意2:不带参数/B
的命令EXIT始终会导致整个命令过程退出,与调用层次结构和Windows命令处理器的启动方式无关-使用参数/K
保持cmd.exe
运行时打开命令提示窗口或使用/C
在命令处理完成后关闭时使用。因此,在批处理文件中应明智地使用不带/B
的exit
(最好永远不要使用)。
注意 3:exit /B
带或不带退出代码都能正常工作,但是在禁用命令扩展的情况下会输出错误消息,如以下代码所示:
@echo off
setlocal DisableExtensions
echo Use command exit /B with command extensions disabled.
exit /B 5
echo This line is not processed anymore.
尽管如此,批处理文件的处理仍然以退出代码值The system cannot find the batch label specified - EOF
5
退出,可以在同一命令提示符窗口中运行下一个命令echo ERRORLEVEL is: %ERRORLEVEL%
查看该值,它输出:ERRORLEVEL is: 5
。似乎首先将指定的退出代码值5
分配给动态变量ERRORLEVEL
,然后由于选项/B
执行goto :EOF
。由于禁用了命令扩展,因此失败并导致出现错误消息,并在批处理文件处理结束时退出,因为在批处理文件中要转到的标签不存在。exit /B
始终有效,无论是否附加了退出代码,但是在禁用命令扩展名时应添加 2>nul
以抑制错误消息,即使用 exit /B 2>nul
(不带退出代码)或 exit /B 5 2>nul
(带退出代码)。
注意 4: ERRORLEVEL
不受 goto :EOF
的影响,但是 Microsoft GOTO 文档对此不作说明。 exit /B #
将 ERRORLEVEL
设置为由 Microsoft 文档 记载的 #
。可以使用 exit /B #
代替 goto :EOF
以使用在调用子程序时从命令行计算的特定退出代码退出子程序,就像使用运算符 &&
或 ||
或在调用带有 if errorlevel X
命令行的下一个命令时一样。然而,通常不需要显式地使用特定的退出代码退出批处理文件或子程序,因为既不 goto :EOF
也不 exit /B
修改当前的 ERRORLEVEL
值。
goto:EOF
或call:Label
。应该始终使用带有空格的goto :EOF
和call :Label
作为命令和标签之间的参数字符串分隔符。原因是goto:EOF
会导致尝试在当前目录中首先查找名为goto:
的文件,然后查找名为goto:EOF
的文件。而不正确的call:Label
命令会导致搜索名为call:
的文件,然后再搜索名为call:Label
的文件。文件系统对于这两个语法错误的命令都会返回两次“无效名称”的错误信息给cmd.exe
。然后cmd.exe
检测到冒号是无效名称的原因,并将命令分割成命令和标签参数,最终成功运行命令。使用goto :EOF
和call :Label
不会引起任何错误的文件系统访问,因为cmd.exe
立即将字符串goto
和call
识别为内部命令。
有关ERRORLEVEL
行为的详细信息,请参见:
GOTO :EOF
是与 exit /B
功能等效的,但这两种形式仅在启用扩展时才有效。测试这一点非常简单:
setlocal DisableExtensions
goto :EOF
与先前的代码相比,这段代码有所改进:
setlocal DisableExtensions
exit /B
GOTO :EOF
返回到与 exit /B
返回相同的位置。:eof 的意思是“文件结束”。它用于使脚本在不执行下面任何命令的情况下完成。
call
命令会新建一个子线程,并且暂停当前线程的执行,直到 call
命令执行完成。call :subroutine
命令会一直执行直到遇到自己的 exit /b
或者程序结束符(EOF),然后再返回到调用者的程序继续执行。打开回显功能可以观察命令的执行顺序,有助于更好地理解。更多关于 call
命令的信息可以参考这个页面,有关批处理函数的教程可以参考这个页面。 - rojoGOTO
和 CALL
具有相同的功能,因此您可以使用 CALL
访问 :EOF
。CALL ::EOF
GOTO
相同(当使用附加分号的CALL
时),实际文件结尾将成为脚本流程的首选点。如果您使用EOF定义了自己的标签/函数,则可以使用单个分号访问它。:EOF
没有太多用处 - 您不能在文件末尾放置代码,因此此行实际上什么也没做(尽管这会影响性能,因为文件末尾被解析)。并且像GOTO
和EXIT /B
一样,这不会在未启用扩展名的情况下工作。
cmd /?
帮助屏幕指示了类似“命令扩展默认启用”的内容... - Aacinigoto :eof
返回 %ERRORLEVEL% == 1,exit /B
也是如此。 - Sandburggoto :eof
还是exit /B
,都不会改变之前的%ERRORLEVEL%值。请参考这个答案了解更多细节... - Aacini