[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
看了随风兄的问题,我认为不是那两句不能同时使用,而是在此句 set var=!var:0= 0 !后,var的长度超过了变量能保存的字符的最大长度,所以导致中途退出。换小一点就不会出现这样的问题。

TOP

由batman所发代码引申出的变量最大长度问题,以下代码由batman、随风、我共同讨论测试得出,结果也只是提出一个猜想,望大家讨论补充!
1、首先给出随风的一个测试代码
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 10000) do (
  4.   set m=a!m!||(echo %%a&pause)
  5.   )
  6. pause
复制代码
结果为8190,这时可能大家会认为最大长度应该是8190。
2、现在做一个小小的改变,把以上代码中的set m=a!m!||(echo %%a&pause)改为set var=a!var!||(echo %%a&pause)。再次运行,按理说结果应该没影响,可是出乎我们的意料,结果为8188。这是为何?参照batcher给出的资料,可以推出变量名和等号都占字节。
3、现在再做出一个改变,把set m=a!m!||(echo %%a&pause),改为set “m=a!m!“||(echo %%a&pause),再次运行,结果是8188。又困惑了,我们一般来看set "str1=str2"和set str1=str2所达到的效果是一样的。再根据资料The maximum individual environment variable size is 8192bytes。我想着要从环境变量的内存空间分配角度来思考了。环境变量分配的最大空间为8192字节。其中包括变量名、等号、引号(如果有的话)、以及变量所包含的字符。
4、为了更加清晰,对刚才代码增加一些。如下:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 10000) do (
  4.   set a=!a!0
  5. )
  6. if "!a:~8181,1!"=="" echo 8181
  7. if "!a:~8182,1!"=="" echo 8182
  8. if "!a:~8183,1!"=="" echo 8183
  9. if "!a:~8184,1!"=="" echo 8184
  10. if "!a:~8185,1!"=="" echo 8185
  11. if "!a:~8186,1!"=="" echo 8186
  12. if "!a:~8187,1!"=="" echo 8187
  13. if "!a:~8188,1!"=="" echo 8188
  14. if "!a:~8189,1!"=="" echo 8189
  15. if "!a:~8190,1!"=="" echo 8190
  16. if "!a:~8191,1!"=="" echo 8191
  17. if "!a:~8192,1!"=="" echo 8192
  18. if "!a:~8193,1!"=="" echo 8193
  19. pause
复制代码
执行后显示为8189,按照刚才的分析,共占有的字节数:8189+1('a')+1('=')=8191,不是8192。这又是为何?再看下面?
5、batman提供的代码:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 10000) do (
  4.   set a=!a!0
  5.   )
  6. set a=!a:0=1!
  7. echo !a!
  8. pause
复制代码
上面代码可以正常运行,可是把上面的代码中set a=!a:0=1!改为:set a=%a:0=1%则提示输入过长。这说明开启变量延迟内存中的分配发生变化,到底是什么变化?期待有人来提供一些资料。
6、第四步分析的还差一个字节,我猜想是不是内存自动占用一个固定的标记字节,来标志是否启动了变量延迟以及其他的一些标志。此也期待有心人来完善。
7、这就是我们的初步分析,可以知道的是单个环境变量的最大的内存分配为8192字节(有资料为证),对于这么多字节的如何分配还有待继续探索。欢迎大家一起来讨论!

[ 本帖最后由 lhjoanna 于 2009-2-21 22:44 编辑 ]

TOP

恩,是笔误啊,谢谢兄指正!

TOP

回复 10楼 的帖子

对于第5步中的代码,如果改为如下,则可以执行。
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 8185) do (
  4.   set a=!a!0
  5.   )
  6. set a=%a:0=1%
  7. echo !a!
  8. pause
复制代码
我也认为和预处理有关,开启变量延迟后,执行到那一句才展开变量,所以set a=!a:0=1!中,把第一个等号右边的理解为一个整体,而set a=%a:0=1%,在执行之前就已经展开,所以 a=%a:0=1%以及右边的%a:0=1%都要满足不能超过最大长度。前面'a'以及'='已经占了2字节。所以%a:0=1%最大为8190字节。其中变量名a、'='、'0'、'1'、标记位各占一个字节,剩下变量a中所包含的字符串最大长度也就是8185了。

TOP

回复 13楼 的帖子

对于微软说法中(Byte)不准确的说法,我想也是可以理解的。技术的发展或多或少都要局限于当时的环境,当时创建字符编码时我想微软也没有考虑到若干年以后全球关系发展的如此迅速,所以也就出现了90年代又花了几年时间来编写Unicode,作为一个统一的国际化编码标准。并且各个国家地区采用的字符集不一致,对于非Unicode的环境下采用活动代码页来进行编码的转换。兄测试下如下代码:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 10000) do (
  4.   set m=a人!m!||(echo %%a&pause)
  5.   )
  6. pause
复制代码
结果为4095,也就是8190的一半。我们可以理解为8192是按字符算的,但是这确实涉及到我们经过活动代码页936的转换后,环境变量在内存中是如何分配的。比如单字节集中空格表示为20H,而经过转换后单字节字符与双字节字符应该如何统一,按原样表示还是扩充为双字节0020H。对于此我没有研究过,还需要再在网上找一些相关资料。

TOP

我认为不是变量类型不匹配,批处理脚本语言也和大部分脚本语言一样,都具有“变量无关、解释执行”等特点。给个例子:
  1. @echo off
  2. set "a=123"
  3. set "b=456"
  4. set /a c=a+b
  5. echo !c!
  6. pause
复制代码

如果按照类型匹配的原则,set /a c=a+b应该报错才对啊。上述的set var=!var:0= 0 !改为set var=!var:"0"=" 0 "!,加引号后空格自动过滤,var依然不变,"0“没有替换为" 0 ",依然是"0",之所以可以运行的原因是因为变量和替换前一样,长度没有变化,没有超过最大长度。此题的根本原因仍是字符串长度问题!

TOP

回复 21楼 的帖子

我上面已经说了啊,set var=!var:"0"=" 0 "!可以正确运行的原因是set之后的var和set之前的var一模一样,根本没有变化。长度没有发生变化,当然可以正确运行。其次解释一下为什么长度没有发生变化:我上面说到是引号自动对空格过滤。今天回来又验证一下,这种说法是不对的。引号没有过滤空格,长度不变的原因是set var=!var:"0"=" 0 "!中,set把"0"做为被替换的变量,在var中找不到"0",所以根本没有发生变化。举两个个例子:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set "var=123456789"
  4. set var=!var:"1"=" 5 "!
  5. echo !var!
  6. pause
复制代码
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. color 1f
  4. set "var=123456789"
  5. set var=!var:1=" 5 "!
  6. echo !var!
  7. pause
复制代码
你提出的:
【1】If you use any of the logical or modulus operators, you will need to
enclose the expression string in quotes.  给个例子:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set a=5
  4. set /a "a*=5,a<<=5"
  5. echo !a!
  6. pause
复制代码
这时需要把表达式用引号括起来,否则出错。
【2】The maximum total environment variable size for all variables, which includes variable names and the equal sign, is 65,536KB.
这句话我的理解为一个程序中所定义的所有环境变量所占用的内存空间不能超过64M。

TOP

回复 24楼 的帖子

不知errorlevel的问题有什么进展,是不是涉及到for解释机制的问题了?

TOP

返回列表