Board logo

标题: [原创] 什么时候使用延迟变量?为什么要使用? [打印本页]

作者: novaa    时间: 2007-11-12 16:44     标题: 什么时候使用延迟变量?为什么要使用?

我看到很多P的开头就是 setlocal EnableDelayedExpansion
不明白到底有什么作用
查了下资料
找到如下(自CN-DOS的WILL SORT)
  1. 在许多可见的官方文档中,均将使用一对百分号闭合环境变量以完成对其值的替换行为称之为“扩展(expansion)”,这其实是一个第一方的概念,是从命令解释器的角度进行称谓的,而从我们使用者的角度来看,则可以将它看作是引用(Reference)、调用(Call)或者获取(Get)。
  2. 而命令解释器是扩展环境变量的行为大致如下:首先读取命令行的一条完整语句,在进行一些先期的预处理之后,命令被解释执行之前,会对其中用百分号闭合的字符串进行匹配,如果在环境空间中找到了与字符串相匹配的环境变量,则用其值替换掉原字符串及百分号本身,如果未得到匹配,则用一个空串替换,这个过程就是环境变量的“扩展”,它仍然属于命令行的预处理范畴。
  3. 而一条“完整的语句”,在NT的命令解释器CMD中被解释为“for if else”等含有语句块的语句和用“& | && ||”等连接起来的复合语句。
  4. 因此,当CMD读取for语句时,其后用一对圆扩号闭合的所有语句将一同读取,并完成必要的预处理工作,这其中就包括环境变量的扩展,所以在for中的所有语句执行之前,所有的环境变量都已经被替换为for之前所设定的值,从而成为一个字符串常量,而不再是变量。无论在for中将那些环境变量如何修改,真正受到影响的只是环境变量空间,而非for语句内部。
  5. 而为了能够在for语句内部感知环境变量的动态变化,CMD设计了延迟的环境变量扩展特性,也就是说,当CMD读取了一条完整的语句之后,它不会立即执行变量的扩展行为,而会在某个单条语句执行之前再进行扩展,也就是说,这个扩展行为被“延迟”了。
  6. 延迟环境变量扩展特性在CMD中缺省是关闭的,开启它的方法目前有两个:一是CMD /vff(此处说法有误,应为 CMD /vn——namejm 注),它会打开一个新的命令行外壳,在使用exit退出这个外壳之前,扩展特性始终有效,常用于命令行环境中;二是setlocal EnableDelayedExpansion,它会使环境变量的修改限制到局部空间中,在endlocal之后,扩展特性和之前对环境变量的修改将一同消失,常用于批处理语句中。
复制代码
但是还是不太清楚到底应该这么用
希望高手能举几个列子引导下

[ 本帖最后由 xxlxltrps 于 2007-11-16 12:16 编辑 ]
作者: youxi01    时间: 2007-11-12 18:10

正在准备写一篇 有关 延迟变量使用 示例方面的文章(下周可能会出来吧?!),不过暂时没时间,要做的工作太多!

等下如果有空的话,我就先举几个例子吧!
作者: youxi01    时间: 2007-11-12 18:27

废话少说,先让我们来看一段代码:
  1. @echo off
  2. set /a num=0
  3. for /l %%i in (1 1 3) do (
  4.      Rem ================================
  5.      set /a num+=1
  6.      Rem 原意是变量num的值每次都加1
  7.      Rem ================================
  8.      echo %num%
  9. )
  10. pause>nul
复制代码
先猜猜看,运行之后的结果是什么呢?
你是不是认为它会显示:1 2 3 呢?我想大部分人会这么认为。
你再将以上代码保存为批处理文件,运行,看看结果。
你会看到,显示的结果并不是意料中的 1 2 3 而是 0 0 0,这个是为什么呢?
原来这个是因为,批处理在处理for 或者if 语句中的变量时,先要进行预处理,把其中的用%%括起来的变量,先替换为语句之前的变量(如上面的代码,for语句中的%num%早就被替换为语句前的 值:0),所以,for语句运行时,虽然已经给变量加了1,但是,值却不变(因为echo %num%中的%num%早已被替换为:0了)。

那么,要实现(for或者if)语句中的变量实时的变化(如这里,我就要将1 2 3 显示出来)要怎么办呢?那就要起用延迟变量,先在批处理中申明:setlocal enabledelayedexpansion
然后,将语句:echo %num%改成!num!(也就是将“%”改成“!”),这样就可以达到效果了,演示代码:
  1. @echo off
  2. Rem ''''///////下面先申明起用延迟变量/////////////
  3. setlocal enabledelayedexpansion
  4. set /a num=0
  5. for /l %%i in (1 1 3) do (
  6.      Rem ================================
  7.      set /a num+=1
  8.      Rem 变量num的值每次都加1
  9.      Rem ================================
  10.      Rem '''''''//////////////////下面的变量不能再用"%"括起来,而应该用"!"////////////
  11.      echo !num!
  12. )
  13. pause>nul
复制代码
以上的解说到此为止,时间仓促,词不尽意,还有什么不明白的,跟贴说明。

归纳总结:
1、为什么要用延迟变量?
让if语句和for语句中的变量实时变化;
2、什么时候用延迟变量?
一般是用在 for 语句和 if 语句中;
3、怎么用延迟变量?
先在批处理中申明起用延迟变量:setlocal enabledelayedexpansion
然后将 for 语句、if语句中的变量用两个"!"括起来即可
作者: novaa    时间: 2007-11-12 21:43


讲的很清楚
呵呵
谢谢了
作者: 随风    时间: 2007-11-16 03:30

看看你原帖中的开头部分。
改标题啊!!!
不要使用这种“关于某某某某的问题”这种“万能标题”

作者: novaa    时间: 2007-11-16 12:19

Re 随风:
谢谢提醒
以后一定记住
作者: onebat    时间: 2008-8-9 00:28

讲的很清楚,我不是给了灌水,而是为了给自己打标记.记下那些是看过的.
作者: ahongguo    时间: 2009-1-4 15:28

让我又有了收获   那例子的确不错
作者: hlzj88    时间: 2012-11-21 21:28

原则上不挖坟贴
但我的确是带着迷糊搜索来看到这篇文章的,理解力不行,上面的例子自己运行了还是迷糊,突然开窍,加上自己的理解,对上面的例子做了添加,来跟帖,目的是希望以后看贴的人能通过我的这个例子轻松愉快的理解这个不容易理解的问题。代码如下,须全文复制并运行来理解。
  1. @echo off
  2. echo.
  3. echo 这个需要源码和运行两者对比来理解变量和变量延迟以及什么时候用^%% 什么时候用^!
  4. echo.
  5. echo 以下代码原意是变量num的值每次都加1
  6. echo.
  7. echo 现在是没有开启变量延迟的效果
  8. echo.
  9. set /a num=0
  10. for /l %%i in (1 1 3) do (
  11.      set /a num+=1
  12.      echo %num%        这是^%%num^%% 加1没效果
  13.      echo !num!    这是!num! 没有变化
  14.      echo.
  15. )
  16. echo.
  17. echo 没有启用变量延迟,返回的结果就没有变化
  18. echo for没有把!num!当一个值来查找显示 而只是当一串字符来显示
  19. echo.
  20. echo.
  21. echo 按任意键看另一个效果  查看上下源码主体来分辨不同之处
  22. pause>nul
  23. echo.
  24. echo.
  25. echo 启用延迟变量后 循环会主动去查找num变化后的新值 并且调用来显示
  26. echo.
  27. echo 对于这样的 (数据会变化的变量)的调用 就再不能使用^%%来调用 而要用^!来调用
  28. echo.
  29. echo 因此下面的变量不能再用^%%括起来,而应该用^!括起来
  30. ping /n 5 127.1>nul
  31. echo.
  32. echo.
  33. echo.
  34. echo 下一行代码先申明启用变量延迟 启用后 以至于都不能通过特别处理来显示!num!
  35. setlocal enabledelayedexpansion
  36. echo.
  37. echo 以下代码原意是变量num的值每次都加1
  38. echo.
  39. set /a num=0
  40. for /l %%i in (1 1 3) do (
  41.      set /a num+=1
  42.      echo %num%        这是^%%num^%% 加1没效果
  43.      echo !num!        这是叹号num叹号 有变化
  44.      echo.
  45. )
  46. echo.
  47. echo 对源码的比较可见只加了一句话 声明启用了变量延迟 for就查找num的新值来显示
  48. pause>nul
复制代码
如果看到的人能轻松理解这个问题,请谢谢为论坛操劳的各位版主和坛主。




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2