Board logo

标题: 批处理变量延迟使用分析 [打印本页]

作者: cjiabing    时间: 2010-9-3 23:34     标题: 批处理变量延迟使用分析

写得不是很到位,有空再改改。
使用方法:一边运行代码,一边阅读代码,两者对照阅读。
  1. @echo off
  2. echo.
  3. echo.
  4. echo                             变量延迟使用分析
  5. echo.
  6. echo.
  7. echo      启用变量延迟的方法:
  8. echo      1、启用之前使用“setlocal EnableDelayedExpansion”声明/开启。
  9. echo      2、启用变量延迟之后,变量的百分号要换成感叹号。
  10. echo.
  11. echo      使用变量延迟的情况:
  12. echo      1、用于复合命令中,如FOR与SET组成的复合命令;(参考案例3和4)
  13. echo      2、用于SET转换变量时,如处理同一变量的SET中;(参考案例5和6)
  14. echo      3、用于扩展(延迟)变量设置的适应范围,
  15. echo         使其在循环等语句和时间环境中可以执行。(参考案例2、5和9)
  16. echo.
  17. echo      停止变量延迟的方法:
  18. echo      使用“endlocal”终止变量延迟。
  19. echo.
  20. echo.      
  21. echo               (使用方法:执行BAT和使用TXT对照阅读)
  22. echo    ___________________________________________________________________________
  23. pause>nul
  24. echo.
  25. echo     1、启用变量延迟之前——成功  
  26. echo.
  27. for /f  "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do echo %%i
  28. pause>nul
  29. echo.
  30. echo     2、启用变量延迟之前——失败
  31. echo.
  32. for /f  "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
  33. set var=%%i
  34. echo %var%
  35. )
  36. ::按道理已经在“set var=%%i”这里转换%%i了,“echo %var%”会成功,但实际上批处理跳过了这个SET,直接执行了ECHO,所以失败。
  37. ::为什么会直接跳过SET呢?我不知道。在FOR和SET的组合中,FOR经常会做跳跃运动,直接跳过SET。
  38. ::其实,也不完全是跳跃,实际上“set var=%%i”执行成功了,它在后面的案例9中成功复出;“echo %var%”也执行成功了,它显示了字符“var”。但是两者之间没有建立起关系,没有达到我们的理想。
  39. ::解决的办法就是开启变量延迟,命令FOR必须先SET,然后ECHO,按规定办事,不能跳槽。
  40. ::具体参考后面案例5和案例9
  41. pause>nul
  42. setlocal EnableDelayedExpansion
  43. echo.
  44. echo     3、启用变量延迟之后——对比以下三个ECHO结果
  45. echo.
  46. for /f  "tokens=1,2,3" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
  47. set var1=%%i
  48. set var2=%%j
  49. set var3=%%k
  50. echo %%i %%j %%k——成功
  51. echo %var1% %var2% %var3%                ——失败
  52. echo !var1! !var2! !var3!——成功
  53. )
  54. ::开启变量延迟之后,原来的变量还可以使用。
  55. ::但用SET转换变量之后,变量不再使用百分号界定,而是用感叹号界定。这是许多新手很容易不注意的地方。
  56. ::为什么一定要把变量的百分号换成感叹号?I DON'T KNOW。或许是变量延迟喜欢标新立异吧,要不人家怎么知道它是变量延迟?~
  57. pause>nul
  58. setlocal EnableDelayedExpansion
  59. echo.
  60. echo     4、为什么要转换变量?——对比以下三个ECHO结果
  61. echo.
  62. for /f  "tokens=1,2,3" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
  63. set var1=%%i
  64. set var2=%%j
  65. set var3=%%k
  66. echo %%%i:~4,3%——失败
  67. echo !%%i:~4,3!——失败
  68. echo !var1:~4,3!——成功
  69. )
  70. ::因为使用原来的变量“%%i”无法截取字符串,只好用SET转换变量。
  71. ::在FOR中,“%%i”经常失效,所以SET才了用武之地。
  72. pause>nul
  73. echo.
  74. echo     5、未启用变量延迟的情况下
  75. echo.
  76. set var=牛&echo   1  实际上:牛——%var%:  显示结果
  77. set var=猪&echo   3  实际上:猪——%var%:显示结果
  78. set var=羊&echo   2  实际上:羊——%var%:显示结果
  79. set var=马&echo   4  实际上:马——%var%:显示结果
  80. set var=人&echo   5  实际上:人——%var%:显示结果
  81. set var=人&&echo   6  实际上:人——%var%:显示结果
  82. echo   7                %var%:显示结果
  83. ::此案例证明了,批处理是“以行为处理”的模式。
  84. ::上一行设定变量,下一行使用变量。上下行是指,紧邻的上一行命令和下一行命令,不是相隔开的行。
  85. ::即使在使用“&”的情况下,其处理时间的先后顺序未改变,其结果也未变。
  86. ::“&”可以改变批处理的“上下行”的处理模式,将其转换成“前后句”的处理模式。
  87. ::但此处“&”失效了,因为ECHO的结果直接跳过了“&”前的“SET”,它使用的是上一句的“SET”。
  88. ::“&&”相当于“IF”为真的判断,当前一命令成功时执行后一命令,因此显示结果同前。
  89. ::需要注意的是,第一行的“%var%”在独立的BAT中,显示为空,但在这个批处理中,它显示的却是案例2的“中华人民共和国万岁 万岁 万万岁”。
  90. ::为什么“set var=%%i”在FOR中的下一行“echo %var%”没有成功,却跨越几十行代码在这里执行成功了呢?
  91. ::这个可能与FOR的机制有关,在FOR中,输出变量是统一由输入变量确定的,SET改变了输出变量,但在循环过程中被忽略了。
  92. ::具体参考案例6和9。
  93. pause>nul
  94. setlocal EnableDelayedExpansion
  95. echo.
  96. echo     6、启用变量延迟的情况下
  97. echo.
  98. set var=牛&echo   1  实际上:牛——!var!:显示结果
  99. set var=猪&echo   3  实际上:猪——!var!:显示结果
  100. set var=羊&echo   2  实际上:羊——!var!:显示结果
  101. set var=马&echo   4  实际上:马——!var!:显示结果
  102. set var=人&echo   5  实际上:人——!var!:显示结果
  103. set var=人&&echo   6  实际上:人——!var!:显示结果
  104. echo   7                !var!:显示结果
  105. ::开启变量延迟之后,“SET”和“&”都获得了执行的时间,ECHO在等待前一句的“SET”执行成功时才执行。这次它不可以跳级了。
  106. ::批处理的处理模式由“上下行”的模式转变为“前后句”的模式。
  107. ::变量延迟,其实应该这样理解,在遇到指定变量时,延迟原命令的执行时间,提前(预先、优先)处理涉及指定变量的命令,再按原来的时间顺序执行。
  108. pause>nul
  109. setlocal EnableDelayedExpansion
  110. echo.
  111. echo     7、处理字符串
  112. echo.
  113. for /f %%i in ("我十分喜欢批处理") do (
  114. set var=%%i
  115. for /l %%a in (0,1,10) do (
  116. set str=!var:~%%a,1!
  117. if defined str echo !str!
  118. )
  119. )
  120. ::此代码由两个FOR组成复合结构。“for /f ”用于解析“我十分喜欢批处理”,“for /l”用于输出数字。
  121. ::为什么需要数字?因为在截取字符(“set str=!var:~%%a,1!”)时需要界定字符的偏移量,而该偏移量是一串自然数,可以用“for /l”实现。
  122. ::按照批处理通常的处理模式,它会从第一行一直执行到最后一行,但是在两个FOR组合中,它的这个顺序被改变了。
  123. ::因为FOR的处理模式是,从集合中提取变量逐一执行,依此循环而止。但FOR中有FOR,它的顺序被第二次改变。FOR中还有SET,它的顺序被第三次改变。
  124. ::据前面案例所知,不启用变量延迟,变量只执行最后一个(一行)的变量设置,前面和中间的同一变量因为跨行而被跨跃过去,无法实现。
  125. ::整个过程比较啰嗦,不好解释,具体参考案例9。
  126. pause>nul
  127. echo.
  128. echo     8、setlocal与endlocal
  129. echo.
  130. set a=1
  131. set b=2
  132. rem 开始临时变量设置
  133. setlocal
  134. set a=3
  135. set b=4
  136. echo %a%
  137. echo %b%
  138. rem 结束临时变量设置
  139. endlocal
  140. echo %a%
  141. echo %b%
  142. ::借用“风行者 ”的代码。具体使用endlocal的情况不是很清楚,因为基本上没用到它。
  143. ::setlocal最多可以使用32次,也就是setlocal的最大递归数是32,使用endlocal来结束临时变量设置。
  144. pause>nul
  145. echo.
  146. echo     9、变量转换对比
  147. echo.
  148. set var=不怕中国城管来抓你,就怕菲律宾警察来救你!
  149. for /f  "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
  150. set var=%%i
  151. set str=%%i
  152. set inf=%%i
  153. set opq=%%i&echo  一   %var%  %str%  %inf%  %opq%
  154. set abc=芝加哥经济学派
  155. echo  二   %var%  %str%  %inf%  %opq%  %abc%
  156. )
  157. echo  三   %var%  %str%  %inf%  %opq%  %abc%
  158. ::原来有效的“set var=%%i”和“echo %var%”在FOR之中失效了。
  159. ::未启用变量延迟的FOR之中,上下行之间失去了直接关联,因此SET的变量被挂起。
  160. ::可能的情况是,FOR从集合中提取第一个变量“中华人民共和国万岁”,然后逐一执行DO后面括号里的每行命令。
  161. ::也就是说,此时的“set var=%%i”不是与它上下行的命令“echo %var%”产生关系,而是与集合内的字符串“中华人民共和国万岁”发生作用。
  162. ::DO后面的命令行并非自成一体的,它受到了FOR的控制,它的顺序被改变了。
  163. ::它们不是真正意义上的上下行关系,只是一种形式上的上下行关系。此时的变量延迟有点“拨乱反正”的意义。
  164. ::如案例中的“set abc=芝加哥经济学派”,在FOR中ECHO无效。启用变量延迟之后,变量设置被继续保留,在FOR进行一下循环的时候终于发生了作用。
  165. ::此案例告诫我们,在一个BAT中,应当尽量避免使用同一“变量名称”,以免造成前后混乱。
  166. ::我前段时间就因此吃亏,因为使用CALL,CALL同一命令时变量是相同的,在CALL前的变量设置延续到了CALL之后的变量之中,给我制造了许多麻烦。
  167. pause>nul
  168. setlocal EnableDelayedExpansion
  169. echo.
  170. echo     10、变量延迟中的变量变化
  171. echo.
  172. set var=不怕中国城管来抓你,就怕菲律宾警察来救你!
  173. for /f  "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
  174. set var=%%i
  175. set str=%%i
  176. set inf=%%i
  177. set inf=Verygood
  178. set opq=%%i&echo  一   1!var!  2!str!  3!inf!  4!opq!
  179. set abc=芝加哥经济学派
  180. echo  二   1!var!  2!str!  3!inf!  4!opq!  5!abc!
  181. )
  182. echo  三   1%var%  2%str%  3%inf%  4%opq%  5%abc%
  183. ::启用变量延迟之后,各个变量的设置都得到了保留,而之前变量的设置则被忽略了。
  184. pause>nul
  185. exit
复制代码

作者: 消失在风中    时间: 2010-9-4 04:01

哥,有个地方出错了!
作者: Batcher    时间: 2010-9-4 16:05     标题: 回复 2楼 的帖子

能否直接告诉楼主哪个地方出错了?
作者: cjiabing    时间: 2010-9-4 22:01

原帖由 Batcher 于 2010-9-4 16:05 发表
能否直接告诉楼主哪个地方出错了?

谢谢大大,原来想写得简单明白一点的,后来自己都搞糊涂了,写得不着边际了,呵呵1~




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