标题: [其他] [分享]批处理FOR语句块中使用标签的总结 [打印本页]
作者: applba 时间: 2011-5-23 18:31 标题: [分享]批处理FOR语句块中使用标签的总结
0、for的语句块中可以使用标签吗?可以,但是不能随便用。
1、不要将标签或::注释放在FOR语句块的末尾。
例如:
@echo off
for /l %%i in (1,1,10) do (
echo %%i
:done
)
pause
运行时提示:“此时不应有 ) ”。
2、不要在FOR语句块中使用 goto+标签 来实现跳转或者循环。
例子:
@echo off
setlocal enabledelayedexpansion
for /l %%i in (1 1 1000000) do (
goto :eof
)
pause
运行后发现并不能马上退出FOR循环。
解释
for语句体在执行过程中第一次遇到goto语句时,会忽略其后面所有的语句,并只进行循环变量的迭代。
迭代完成后,循环变量重新变为为定义的状态,然后控制权由for语句转移给goto语句。
也就是说goto命令总是最后被执行,而且只会执行一次。
例子:
@echo off
setlocal enabledelayedexpansion
for /l %%i in (1,1,10) do (
set /a a=0
:loop
echo %a%
set /a a=a+1
if not "%%i"=="!a!" goto loop
)
pause
运行后发现进入无限循环。
原因在于执行goto时迭代过程已经完成,%%i(预处理后是%i)是未定义的,%%i不可能和!a!相等。
3、可以在FOR语句中使用Call语句来调用内部或外部的标签
例子:
@echo off
setlocal enabledelayedexpansion
for /l %%i in (1,1,10) do (
set a=%%i
call :loop
:loop
echo !a!
)
注意上面的例子中echo !a!会被重复运行一次。
之所以不直接用echo %%i是因为call“看不见”%%i。
作者: CrLf 时间: 2011-5-23 18:46
在for中使用goto就已经跳出循环,原来的for不再起效
作者: applba 时间: 2011-5-23 18:53
无论如何变量的迭代总是要完成的,完成后才会正式跳出for语句体。- @echo off
- setlocal enabledelayedexpansion
- for /l %%i in (1 1 1000000) do (
- goto :eof
- )
- pause
复制代码
你应该明白1000000的含义,运行时你注意光标,要闪几秒到十几秒才会退出的。
作者: CrLf 时间: 2011-5-23 18:56
我的意思是...
好吧,算了
作者: applba 时间: 2011-5-23 19:17
4# zm900612
大哥,我说过啊,迭代完成后,%%i重新变成为未定义,控制权已经移交到goto了……
所以在执行goto时,for自然是不起作用了,和你不是一个意思吗?
作者: CrLf 时间: 2011-5-23 19:48
for中的goto要在迭代完才执行是常识了,刚才只是想说尽管是理论研究,一切从简,我想比尔都没考虑到那些控制权之类的东西,有些东西除非真的有非常微妙的区别,没必要去划分太细。
比如甲兵兄的某个关于for命令的帖子,我认为不需要写那么多,只要告诉大家“=”、“,”、“ ”等等是分隔符,而“?”和“*”这两个通配符在不带开关的for中起到统配文件的作用云云,我想只需要把这两句本质性的结论讲清楚就行了,特地为此把所有特殊情况列举出来可能没有太大的必要。
要想理解纷繁复杂的现象,只要抓住它最本质的规律就够了,我想,这也是批处理编写时的首要任务。
作者: techon 时间: 2011-5-24 01:27
本帖最后由 techon 于 2011-5-24 14:37 编辑
@echo off
setlocal enabledelayedexpansion
for /l %%i in (1 1 1000000) do (
goto :eof
)
pause ...
值肯定是先赋了,要不不可能这么慢
要说语句流程应该是go语句影响了for 内变量%%i 的正确传递
goto语句完成后 cmd 找不到原来已赋值的 %%i 了- @echo off
- setlocal enabledelayedexpansion
- for /l %%i in (5,1,10) do (
- set /a a=0
- set c=%%i
- :loop
- echo %a%
- set /a a=a+1
- echo ---%%%%!i===%%i---
- echo ---"!c!"--- ---"!a!"---&pause
- if not "!c!"=="!a!" goto loop
- )
- pause
- goto :eof
-
- @echo off
- set a=10
- for /l %%C in (1,1,%a%) do (
- echo %%C
- if %%C equ 5 goto :next
- )
- :next
- pause
复制代码
作者: Hello123World 时间: 2011-5-24 13:50
本帖最后由 Hello123World 于 2011-5-24 13:54 编辑
3# applba - @echo off
- setlocal enabledelayedexpansion
- for /l %%i in (1 1 1000000) do (
- set a=%%i
- goto hello
- )
- :hello
- echo !a!
- pause
复制代码
光标确实是停顿了几秒,但值却依然是1而不是1000000,难道执行顺序不是先提取元素(do前括号),然后再对其进行操作(do后括号)。
如果不是这个顺序a因该是空值,如果是这个顺序a值因该为1000000(光标停顿),但a却是1,唯一的解释就是你说的,无论如何for循环的元素都会执行完,即便是不执行do后的操作也要循环完——这还真是怪。
作者: CrLf 时间: 2011-5-24 15:16
8# Hello123World
这段延时包括了对for循环内的语句的预处理耗时,可以对比一下只含goto的for循环与除了goto含有很多其他语句的for循环的耗时,后者一定更慢,也就是说,for的迭代不可打断,用call只是暂时调出,调用完毕后仍会回到for循环中,而goto则是使之后的内容只解释不执行(也就是楼主说的控制权)。
我想,根本原因也许是goto无法打断并跳出语块,曾想要为此做实验,但是除了for这个特殊的语块形式以外,其他的语块都只会有一次预处理,而预处理又是在goto之前的,所以无法区分goto究竟能不能直接跳出语块,伤脑筋。
作者: qzwqzw 时间: 2011-5-24 16:09
本帖最后由 qzwqzw 于 2011-5-24 16:24 编辑
9# zm900612
应该这样理解
goto 跳出了()语句块
但是for又开启了新的语句块
它没有跳出for的循环
因为它无法预知for的循环结束点
如同如来佛祖与齐天大圣一般
- for /l %%i in (1 1 3) do (
- echo %%i 被预处理但不被执行
- if [%%i]==[2] goto :end
- echo %%i 被预处理但不被执行
- )
- echo 不被预处理
- :end
- pause
复制代码
作者: CrLf 时间: 2011-5-24 16:48
唔,有道理,应该把for循环理解成子语块的循环,刚才没想这么细,把整个for循环当成一个语块了
作者: applba 时间: 2011-5-24 23:58
本帖最后由 applba 于 2011-5-25 00:05 编辑
10# qzwqzw
你加上@echo off看看,确实是执行了几次的。- @echo off
- for /l %%i in (1 1 5) do (
- echo 循环变量是%%i 句子1
- if [%%i]==[3] goto :end
- echo 循环变量是%%i 句子2
- )
- :end
- pause
复制代码
所以我的看法是:
执行的时候遇到goto才会中断do后面()中的命令的执行。
当%%i=1和2的时候,goto不会被执行的,所以是会正常的“预处理并执行”。
等于3的时候,goto被执行了,goto后面的那一句echo没有被执行。
同时%%i为4和5的时候,预处理是发生了,但是命令不会被执行。
作者: amwfjhh 时间: 2014-11-11 14:30
FOR是内部命令,是这么说的吧?可不可以这么理解,把FOR看成CMD的一个函数名,这个函数在执行的时候,就会根据in里面的条件把内存区分配好,而它又只提供了一个遍历指针的寻址方式,因此不管你内部逻辑如何变,它都会把运行到FOR那分配的内存查询完,至于执不执行语句,推测可能是CMD的执行语句的地址变了,而FOR还要一个一个地去找它里面的小区块地址是不是主程序的执行地址……
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |