Board logo

标题: [其他] [已解决]批处理SetLocal 的一些疑问与讨论 [打印本页]

作者: greenworld    时间: 2010-12-28 10:45     标题: [已解决]批处理SetLocal 的一些疑问与讨论

最近写了些代码,有时需开启变量延迟,但为了避免处理有!号路径或文件时出错,又不能全开,只能选择性的开了又关,关了再开...于是就发现了SetLocal的一些问题...这里讨论一下
  1. @echo off
  2. set a=ABC
  3. SetLocal EnableDelayedExpansion
  4. set a=IJK
  5. SetLocal DisableDelayedExpansion
  6. echo %a%
  7. pause
复制代码
结果为 IJK
  1. @echo off
  2. set a=ABC
  3. SetLocal EnableDelayedExpansion
  4. set a=IJK
  5. SetLocal DisableDelayedExpansion
  6. echo %a%
  7. pause
  8. SetLocal EnableDelayedExpansion
  9. set a=OPQ
  10. SetLocal DisableDelayedExpansion
  11. echo %a%
  12. pause
复制代码
结果是 OPQ

但是,
  1. @echo off
  2. set a=ABC
  3. SetLocal EnableDelayedExpansion
  4. set a=IJK
  5. SetLocal DisableDelayedExpansion
  6. echo %a%
  7. pause
  8. call :A
  9. echo %a%
  10. pause
  11. goto :eof
  12. :A
  13. SetLocal EnableDelayedExpansion
  14. set a=OPQ
  15. SetLocal DisableDelayedExpansion
复制代码
结果是 IJK

  1. @echo off
  2. set a=ABC
  3. SetLocal EnableDelayedExpansion
  4. set a=IJK
  5. SetLocal DisableDelayedExpansion
  6. echo %a%
  7. pause
  8. call :A
  9. echo %a%
  10. pause
  11. goto :eof
  12. :A
  13. ::SetLocal EnableDelayedExpansion
  14. set a=OPQ
  15. ::SetLocal DisableDelayedExpansion
复制代码
结果却是 OPQ

而下面
  1. @echo off
  2. set a=ABC
  3. SetLocal EnableDelayedExpansion
  4. set a=IJK
  5. SetLocal DisableDelayedExpansion
  6. echo %a%
  7. pause
  8. goto :A
  9. :A
  10. SetLocal EnableDelayedExpansion
  11. set a=OPQ
  12. SetLocal DisableDelayedExpansion
  13. echo %a%
  14. pause
复制代码
结果还是 OPQ

所以大概的结论是,call 会让 SetLocal EnableDelayedExpansion 开辟新的变量空间,此时对环境变量来说,相当于SetLocal...而SetLocal DisableDelayedExpansion则相当于endlocal
作者: hanyeguxing    时间: 2010-12-28 12:00

原帖由 greenworld 于 2010-12-28 10:45 发表
所以大概的结论是,call 会让 SetLocal EnableDelayedExpansion 开辟新的变量空间,此时对环境变量来说,相当于SetLocal...而SetLocal DisableDelayedExpansion则相当于endlocal

enabledelayedexpansion  、 disabledelayedexpansion 参数没有关系。
1,不要频繁使用setlocal,如果不及时Endlocal会造成超过最大允许递归层(xp下是32)
2,每次setlocal本地化时就开启了一个新的(子层)变量空间,并且保存新的变量变化,命令对变量的读写也在当前层(可从父层继承)。
而call返回后对变量的读写则回到了原来(父层)的变量空间。
最大递归层测试:
  1. @echo off
  2. for /l %%a in (1,1,33) do setlocal&echo 第 %%a 层
  3. pause
复制代码
各层之间的继承关系演示:
  1. @echo off
  2. set/a a=1,b=1,c=1
  3. echo 0:%a%,%b%,%c%
  4. call:a
  5. echo 0_:%a%,%b%,%c%
  6. pause&exit
  7. :a
  8. setlocal
  9. set a=2
  10. echo a:%a%,%b%,%c%
  11. call:b
  12. echo a_:%a%,%b%,%c%
  13. goto:eof
  14. :b
  15. setlocal
  16. set b=2
  17. echo b:%a%,%b%,%c%
  18. call:c
  19. echo b_:%a%,%b%,%c%
  20. goto:eof
  21. :c
  22. setlocal
  23. set c=2
  24. echo c:%a%,%b%,%c%
复制代码

[ 本帖最后由 hanyeguxing 于 2010-12-28 19:54 编辑 ]
作者: Batcher    时间: 2010-12-28 13:53

参考:批处理最大限度原样输出含特殊字符的指定行内容
http://bbs.bathome.net/thread-4580-1-1.html
作者: tmplinshi    时间: 2010-12-28 14:03

经测试,只要在子过程使用了 SetLocal 命令(以下任意一句)
    SetLocal
    SetLocal EnableDelayedExpansion
    SetLocal EnableExtensions
子过程中设置的值就不会返回。

为什么会这样呢?
在“SetLocal /?”的帮助中说到,如果在批处理中使用了 SetLocal 命令,那么在批处理结尾会有一个隐含的 ENDLOCAL 被执行。

所以原因应该就是,子过程也被当做是一个批处理的结束,所以当子过程中执行了 SetLocal,子过程结尾处就会执行 EndLocal。

[ 本帖最后由 tmplinshi 于 2010-12-28 14:38 编辑 ]
作者: hanyeguxing    时间: 2010-12-28 14:32

  1. @echo off&setlocal enableDelayedExpansion
  2. for /l %%a in (1,1,8100) do set a=!a!0
  3. echo 完成初始化
  4. for /l %%a in (1,1,90000) do call:a %%a
  5. echo 完成测试
  6. pause&exit
  7. :a
  8. setlocal
  9. echo %1
  10. set #%1=%a%
复制代码
中间没有报任何错,显然子过程结束时执行了 EndLocal 。

[ 本帖最后由 hanyeguxing 于 2010-12-28 14:35 编辑 ]
作者: zqz0012005    时间: 2010-12-28 22:06

你们两个还在讨论这个问题?
对Windows系统自带的手册(主要指Help目录下的东西,还包括虽不直接提供但微软网站可下载且很常用的,如script56.chm)一定要滚瓜烂熟,奸里面的确有很多好东西。

装操作系统一定要尽可能安装原版!集成补丁的也行,但不要装对系统改动太大的,更不要装精简版。
作者: ddddxxxxx    时间: 2011-7-27 16:52

  1. @echo off
  2. set a=ABC
  3. SetLocal EnableDelayedExpansion
  4. set a=IJK
  5. SetLocal DisableDelayedExpansion
  6. echo %a%
  7. pause
  8. call :A
  9. echo %a%
  10. pause
  11. goto :eof
  12. :A
  13. ::SetLocal EnableDelayedExpansion
  14. set a=OPQ
  15. ::SetLocal DisableDelayedExpansion
复制代码
我刚刚接触批处理不久?能帮我解释一下“::SetLocal EnableDelayedExpansion”这里的冒号什么意思吗?为什么运行结果会和上面一个代码不同,这双冒号起了什么作用?
作者: tmplinshi    时间: 2011-7-27 17:02

本帖最后由 tmplinshi 于 2011-7-27 17:14 编辑

回复 7# ddddxxxxx


    双冒号是无效的标签。因为是标签,所以双冒号后面的是标签名;因为是无效标签,所以不会影响正常标签。总之,双冒号是用来注释的。
作者: ddddxxxxx    时间: 2011-7-27 18:50

回复 8# tmplinshi


    谢谢斑竹解释。我又看了相关的东西  ,大致懂了。
作者: taofan712    时间: 2017-3-2 00:18

原来如此,之前阅读一些代码总是看不懂,原来setlocal意义在这里,受教了。




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