GOTO :EOF 返回到哪里?
Posted
技术标签:
【中文标题】GOTO :EOF 返回到哪里?【英文标题】:Where does GOTO :EOF return to? 【发布时间】:2016-09-27 16:58:23 【问题描述】:我试图了解代码中 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
【问题讨论】:
【参考方案1】::eof 表示“文件结束”。它用于使脚本在不执行以下任何命令的情况下完成。
【讨论】:
谢谢!但是循环是如何发生的呢?第二个 GOTO 还说 :eof 不应该说 GOTO :DO 例如? @s6398197atusercall
产生一个子线程并且当前线程的执行暂停直到call
完成。 call :subroutine
一直运行到它自己的 exit /b
或 EOF 到达,此时在调用者处恢复执行。让 echo 打开,您可以观察命令执行的顺序,希望它会更有意义。 See this page 了解有关call
的更多信息,this page 了解有关批处理脚本函数的教程。【参考方案2】:
GOTO :EOF
与exit /B
功能等效,但两种形式都仅在启用扩展时有效。这一点的测试很简单:
setlocal DisableExtensions
goto :EOF
比较以前的代码和现在的代码:
setlocal DisableExtensions
exit /B
这意味着GOTO :EOF
返回到exit /B
将返回的同一点。
【讨论】:
扩展是默认启用的,还是必须明确启用? @MaxCascone:cmd /?
帮助屏幕显示类似“默认启用命令扩展”...【参考方案3】:
:EOF
是 Microsoft 在命令 GOTO 的文档中解释的预定义标签。在命令提示符窗口goto /?
中运行的帮助输出也解释了 End Of File 的这个特殊标签。但是这个预定义的标签只有在默认启用命令扩展的情况下才受支持。
在命令提示符窗口call /?
中运行的帮助输出,当然还有命令CALL 的文档都解释了goto :EOF
应该用于退出用call :Label
调用的子例程。
子程序只不过是嵌入在当前批处理文件中的另一个批处理文件,使用命令call
调用。如果子程序在批处理文件的末尾,则真正的文件末尾标志着子程序的结束。
但是一个批处理文件中可以有多个子程序。
因此,命令解释器需要一个命令来在命令处理中到达特定行时退出子例程并返回调用命令行。 goto :EOF
和 exit /B
都可以在任何地方使用以退出子例程或退出当前的批处理文件处理。
在有问题的批处理代码中,first goto :EOF
需要退出批处理文件处理,而不会在完成循环后意外落入子程序代码。
提问者批处理代码中的secondgoto :EOF
用于退出子程序并在第二行的FOR循环中继续处理。它不退出批处理文件的处理,它只退出子程序的处理。
注意 1: goto EOF
不带冒号要求批处理文件中确实有以:EOF
开头的行,即文件中必须存在标签EOF
。 goto :EOF
总是导致退出子程序/批处理并启用命令扩展,即使批处理文件中有标签 EOF
,因为一行以 :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
在命令提示符窗口中执行此批处理文件会导致输出错误消息:
系统找不到指定的批次标签-EOF
换句话说,没有额外退出代码的exit /B
与goto :EOF
完全相同,因此也依赖于命令扩展。 exit
不带 /B
不带或带退出代码始终有效。
注意 4: ERRORLEVEL
不受 goto :EOF
影响,但 Microsoft GOTO 文档对此主题保持沉默。 exit /B #
由 Microsoft 将 ERRORLEVEL
设置为 #
as documented。 exit /B #
也可以用来代替 goto :EOF
退出子程序,并在调用子程序的命令行上评估特定的退出代码,例如使用运算符 &&
或 ||
或在调用命令行后的下一个命令if errorlevel X
。但是,通常不需要显式退出具有特定退出代码的批处理文件或子例程,因为 goto :EOF
和 exit /B
都不会修改 ERRORLEVEL
的当前值。
注意5:不要在批处理文件中使用goto:EOF
或call:Label
,命令GOTO和CALL之间没有空格(参数 0)和标签(参数 1)。应始终使用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
行为的详细信息,请参阅:
【讨论】:
【参考方案4】:由于GOTO
和CALL
使用相同的功能来查找标签,您也可以选择使用CALL
访问:EOF
:
CALL ::EOF
与GOTO
相同(当CALL
带有额外的分号时)实际的文件结尾将是脚本流的最佳位置。如果您使用 EOF 定义了自己的标签\函数,则可以使用单个分号访问它。
虽然调用:EOF
没有多大用处——你不能在文件末尾添加代码,所以这一行实际上什么也没做(尽管这会影响文件末尾的解析)。正如GOTO
和EXIT /B
一样,如果没有启用扩展,这将无法工作。
【讨论】:
以上是关于GOTO :EOF 返回到哪里?的主要内容,如果未能解决你的问题,请参考以下文章