Board logo

标题: [其他] [分享]批处理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语句体。
  1.   @echo off
  2.         setlocal enabledelayedexpansion
  3.         for /l %%i in (1 1 1000000) do (
  4.         goto :eof
  5.         )
  6.         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 了
  1.   @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%i in (5,1,10)  do (
  4. set /a a=0
  5. set c=%%i
  6. :loop
  7. echo %a%
  8. set /a a=a+1
  9. echo ---%%%%!i===%%i---
  10. echo ---"!c!"--- ---"!a!"---&pause
  11. if not "!c!"=="!a!" goto loop
  12. )
  13. pause
  14. goto :eof
  15. @echo off
  16. set a=10
  17. for /l %%C in (1,1,%a%) do (
  18.   echo %%C
  19.   if %%C equ 5 goto :next
  20. )
  21. :next
  22. pause
复制代码

作者: Hello123World    时间: 2011-5-24 13:50

本帖最后由 Hello123World 于 2011-5-24 13:54 编辑

3# applba
  1.   @echo off
  2.         setlocal enabledelayedexpansion
  3.         for /l %%i in (1 1 1000000) do (
  4.         set a=%%i
  5. goto hello
  6.         )
  7. :hello
  8. echo !a!
  9.         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的循环结束点
如同如来佛祖与齐天大圣一般

  1. for /l %%i in (1 1 3) do (
  2. echo %%i 被预处理但不被执行
  3. if [%%i]==[2] goto :end
  4. echo %%i 被预处理但不被执行
  5. )
  6. echo 不被预处理
  7. :end
  8. 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看看,确实是执行了几次的。
  1. @echo off
  2. for /l %%i in (1 1 5) do (
  3.         echo 循环变量是%%i 句子1
  4.         if [%%i]==[3] goto :end
  5.         echo 循环变量是%%i 句子2
  6. )
  7. :end
  8. 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://www.bathome.net/) Powered by Discuz! 7.2