[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[系统相关] 批处理无法在for中给变量累加赋值?

无法在for中给变量累加赋值?
请教各位一个问题?
写代码时发现cmd的一个奇怪显现,百思不得其解。
看下面的代码,先别运行,诸位能看出语法错误吗?
但第一次pause后,就会退出。。。
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. color 1f
  4. set "var=00000"
  5. for /l %%a in (1 1 10) do set var=!var!!var!
  6. echo !var!
  7. echo 这里可以运行。
  8. pause
  9. color cf
  10. set var=!var:0= 0 !
  11. echo !var!
  12. echo 这无法运行???
  13. pause
复制代码
原因有二
第一、 取消 set var=!var:0= 0 ! 这一句
第二、 for /l %%a in (1 1 10) do set var=!var!!var!
       这句中不能有多个的!var!,改为set var=000!var!就没事
       也就是这两句不能同时出现??
       郁闷。。。。。。
技术问题请到论坛发帖求助!

看了随风兄的问题,我认为不是那两句不能同时使用,而是在此句 set var=!var:0= 0 !后,var的长度超过了变量能保存的字符的最大长度,所以导致中途退出。换小一点就不会出现这样的问题。

TOP

汗啊,,原来是这么简单的问题,
变量赋值的最多应该是8190个,没注意我那代码超过了,,
技术问题请到论坛发帖求助!

TOP

原帖由 随风 于 2009-2-19 15:23 发表
汗啊,,原来是这么简单的问题,
变量赋值的最多应该是8190个,没注意我那代码超过了,,

那小楼兄运行下下面这段代码看(我的机子上能运行出结果):
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set "var=0"
  4. for /l %%a in (1 1 10000000) do set "var=!var!!var!"
  5. echo !var!
  6. pause>nul
复制代码

这总不止8190个字符了吧
***共同提高***

TOP

http://technet.microsoft.com/en-us/library/bb490954.aspx

The maximum individual environment variable size is 8192bytes.

The maximum total environment variable size for all variables, which includes variable names and the equal sign, is 65,536KB.
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

错误信息如下

这里可以运行。
请按任意键继续. . .
输入行太长。
命令语法不正确。

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

set m=“a!m!”||
引号笔误吧 应该是 set "m=a!m!"

[ 本帖最后由 随风 于 2009-2-21 19:05 编辑 ]
技术问题请到论坛发帖求助!

TOP

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

TOP

回复 7楼 的帖子

关于第5点,我认为可能和预处理有关系。
set a=!a:0=1!,预处理时并不展开变量(执行时才进行替换操作),所以输入行长度为该行语句字面长度13。
set a=%a:0=1%,预处理时要先对变量进行展开,展开后的长度显然超过了命令行允许的长度(这个长度应该是8192)。

[ 本帖最后由 zqz0012005 于 2009-2-22 05:22 编辑 ]
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

回复 7楼 的帖子

至于第2点中推断的结论“变量名和等号都占字节”,可以进一步验证:
随风的一个测试代码
  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
复制代码
如果把变量名换成逗号“,”,利用命令行的空子,写成如下形式:
set,=a!,!||(echo %%a&pause)
则结果为8191。
逗号有多重意思,一是作为命令与参数之间必要的分隔符,二就是作为变量名。而系统有时对这种多样性处理不完善,最后的结果认为set,=a!,!语句中没有变量名,于是给变量值多分配了一位。
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

关于取最大长度的一个题外话(先写在这里,整理时再分开或删除吧)
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 8193) do (
  4.   set,=a!,!||(echo !,!&echo !errorlevel!&pause)
  5. )
  6. pause
复制代码
如果换成以下形式
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%a in (1 1 8193) do (
  4.   set,=a!,!
  5.   if !errorlevel! neq 0 (echo !,!&echo !errorlevel!&pause)
  6. )
  7. pause
复制代码
即将||改成errorlevel的形式,结果竟然不同。

这好像是for语句内部errorlevel返回值的问题。以前说过for本身是一个特殊的命令解释程序,但不知这一点有没有讨论过(我以前也发过,但讨论的人不多,我当时的分析也比较混乱,有时间再好好整理一下)。
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

如果用echo命令将变量写到文本中,
!m!长度是8190,而文本中的字符是8189个“a”+2字节的回车换行符(CrLn),结果共8191个字节。
!,!长度是8191,而文本中的字符是8190个“a”+1个回车符(Cr),结果也是共8191个字节。

已经讨论过,微软的说法中“字节(byte)”是不准确的,实际可以为字符。
如果把字母a换成汉字比如“人”,则
!m!长度是8190,而文本中的字符是8189个“人”+2字节的回车换行符(CrLn),结果共(8189*2+2)个字节。
!,!长度是8191,而文本中的字符是8190个“人”+1个回车符(Cr),结果共(8190*2+1)个字节,比上面多1个字节。

[ 本帖最后由 zqz0012005 于 2009-2-22 06:47 编辑 ]
命令行参考:hh.exe ntcmds.chm::/ntcmds.htm
求助者请拿出诚心,别人才愿意奉献热心!
把查看手册形成条件反射!

TOP

回复 13楼 的帖子

可能是当年微软写帮助文档的时候,没有考虑到每个汉字占两个字节^_^
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

我有没有看错时间,呵呵,各版主辛苦了,颇有研究哈

TOP

返回列表