(Windows批处理)如果块内转到很奇怪的行为
如果我拿下面的Windows批处理代码片段并运行它:
echo foo if 1 == 1 ( echo bar goto asdf :asdf echo baz ) else ( echo quux )
我期望的输出是:
foo bar baz
但是,我得到:
foo bar baz quux
如果我注释掉goto asdf
行,它会给出我期望的结果。 echo quux
行不应该被执行,为什么goto会导致这种情况发生?
更新:为什么它的价值,这是一个解决方法,正确做我原本的目的:
goto BEGIN :doit echo bar goto asdf :asdf echo baz goto :EOF :BEGIN echo foo if 1 == 1 ( call :doit ) else ( echo quux )
但是,这不能回答我原来的问题。
CALL或GOTO的目标不应该在括号内的块语句内。 这是可以做到的,但正如你所看到的,结果可能不会成为你想要的。
整个IF(…)ELSE(…)结构被parsing,并在任何处理之前加载到内存中。 换句话说,它在逻辑上被视为一行代码。 分析之后,CMD.EXE期望从IF / ELSE结构之后的下一行开始继续parsing。
parsing阶段之后,复杂命令从内存中执行。 IF子句正确处理,ELSE子句被正确跳过。 但是在IF(true)子句中,执行GOTO :asdf
,所以CMD.EXE正式开始扫描标签。 它从IF / ELSE结尾开始,扫描到文件底部,循环回到顶部,扫描直到find标签。 标签恰好在您的IF子句中,但标签扫描器对这个细节一无所知。 所以当复杂的命令从内存执行完成时,批处理将从标签而不是从复杂IF / ELSE的末尾恢复。
所以在这一点上批处理器看到并执行接下来的几行
echo baz ) else ( echo quux )
巴兹是回声,所以是quux。 但是您可能会问,“为什么不) else (
否则)
产生语法错误,因为它们现在不平衡,不再作为较大的IF语句的一部分进行分析?
那是因为如何)
被处理的。
如果遇到打开(
活动时)
,则按照您的预期处理)
。
但是,如果parsing器正在等待一个命令,并且发现a )
当没有活动的开放(
,那么)
被忽略,并且行的其余部分的所有字符都被忽略! 现在有效地发挥了REM的作用。
一组括号内的任何内容都被认为是一行,处理,解释和执行一击。 你的脚本到达goto asdf
并跳出该块/行。 在标签:asdf
,没有括号,所以它开始逐行阅读线。 它到达else
,但没有, if
之间:asdf
和else
所以它忽略它。
为了防止这样的问题,我总是使用goto
或call
if
和for
语句,而不是块。 这样可以解决进一步的goto
语句问题,也可以用variables分析很多问题。
要使用goto
:
echo foo if 1 == 1 goto bar echo quux goto nextbit :bar echo bar goto asdf :asdf echo baz :nextbit :: more script...
或者使用call
:
echo foo if 1 == 1 (call :bar) else (call :quux) :: more script... exit /b :bar echo bar goto asdf :asdf echo baz exit /b :quux echo quux exit /b
在这种情况下,事实certificate,这与IF语句中循环的嵌套和结构较差有关,正如上面的https://stackoverflow.com/users/1012053/dbenham所清楚解释的那样。;
这就是说,由于这个问题,我想出了另外一个类似的考虑…请看看下面的问题和后续的解决方法: “。在这个时候是意外的”从批处理脚本行'生成如果存在[文件](。 ..
解决scheme只是在IF语句块内的ECHO行上处理'('和')'。
重点是,在排除IF(也可能是FOR)语句时,请考虑将特殊字符作为可能的问题来源。
HTH