(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之间:asdfelse所以它忽略它。

为了防止这样的问题,我总是使用gotocall iffor语句,而不是块。 这样可以解决进一步的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