如果我使用以下Windows批处理代码段并运行它:
echo foo
if 1 == 1 (
echo bar
goto asdf
:asdf
echo baz
) else (
echo quux
)Run Code Online (Sandbox Code Playgroud)
我期望的输出是:
foo
bar
bazRun Code Online (Sandbox Code Playgroud)
但相反,我得到:
foo
bar
baz
quuxRun Code Online (Sandbox Code Playgroud)
如果我注释掉该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
)Run Code Online (Sandbox Code Playgroud)
但是,这不符合我原来的问题.
dbe*_*ham 29
CALL或GOTO的目标永远不应该在括号内的块语句内.它可以完成,但正如你所看到的,结果可能不是你想要的.
整个IF(...)ELSE(...)构造在处理任何构造之前被解析并加载到内存中.换句话说,它在逻辑上被视为一行代码.在解析之后,CMD.EXE期望从IF/ELSE构造之后的下一行开始继续解析.
在解析阶段之后,从内存执行复杂命令.正确处理IF子句并正确跳过ELSE子句.但是在IF(true)子句中,你执行a GOTO :asdf,所以CMD.EXE开始扫描标签.它从IF/ELSE结束开始,扫描到文件的底部,循环回到顶部,然后扫描直到找到标签.标签恰好在您的IF子句中,但标签扫描器对该细节一无所知.因此,当复杂命令从内存完成执行时,批处理将从标签而不是从复杂IF/ELSE的末尾恢复.
因此,此时批处理器会查看并执行接下来的几行
echo baz
) else (
echo quux
)
Run Code Online (Sandbox Code Playgroud)
baz得到了回应,quux也是如此.但是你可能会问,"为什么不) else (和/或)生成语法错误,因为它们现在是不平衡的,不再被解析为更大的IF语句的一部分?
那是因为如何)处理.
如果遇到打开的(活动状态),则会按)预期处理.
但是如果解析器期望一个命令并找到一个)没有活动打开的时间(,那么)它将被忽略,并且该行的其余部分上的所有字符都将被忽略!实际上,)现在作为REM声明起作用.
括号内的任何内容都被视为单行,在一次点击中处理,解释和执行.您的脚本到达goto asdf并跳出该块/行.在标签处:asdf,没有支架,因此它开始逐个读取线条.它达到了else,但没有if介于两者之间:asdf,else所以它忽略了它.
为了防止这样的问题,我总是使用goto或callon if和for语句,而不是块.这可以用进一步的goto陈述来解决问题,也可以用变量来解决很多问题.
使用goto:
echo foo
if 1 == 1 goto bar
echo quux
goto nextbit
:bar
echo bar
goto asdf
:asdf
echo baz
:nextbit
:: more script...
Run Code Online (Sandbox Code Playgroud)
或者使用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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12400 次 |
| 最近记录: |