标题: 批处理变量延迟使用分析 [打印本页]
作者: cjiabing 时间: 2010-9-3 23:34 标题: 批处理变量延迟使用分析
写得不是很到位,有空再改改。
使用方法:一边运行代码,一边阅读代码,两者对照阅读。
-
- @echo off
- echo.
- echo.
- echo 变量延迟使用分析
- echo.
- echo.
- echo 启用变量延迟的方法:
- echo 1、启用之前使用“setlocal EnableDelayedExpansion”声明/开启。
- echo 2、启用变量延迟之后,变量的百分号要换成感叹号。
- echo.
- echo 使用变量延迟的情况:
- echo 1、用于复合命令中,如FOR与SET组成的复合命令;(参考案例3和4)
- echo 2、用于SET转换变量时,如处理同一变量的SET中;(参考案例5和6)
- echo 3、用于扩展(延迟)变量设置的适应范围,
- echo 使其在循环等语句和时间环境中可以执行。(参考案例2、5和9)
- echo.
- echo 停止变量延迟的方法:
- echo 使用“endlocal”终止变量延迟。
- echo.
- echo.
- echo (使用方法:执行BAT和使用TXT对照阅读)
- echo ___________________________________________________________________________
- pause>nul
- echo.
- echo 1、启用变量延迟之前——成功
- echo.
- for /f "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do echo %%i
- pause>nul
- echo.
- echo 2、启用变量延迟之前——失败
- echo.
- for /f "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
- set var=%%i
- echo %var%
- )
- ::按道理已经在“set var=%%i”这里转换%%i了,“echo %var%”会成功,但实际上批处理跳过了这个SET,直接执行了ECHO,所以失败。
- ::为什么会直接跳过SET呢?我不知道。在FOR和SET的组合中,FOR经常会做跳跃运动,直接跳过SET。
- ::其实,也不完全是跳跃,实际上“set var=%%i”执行成功了,它在后面的案例9中成功复出;“echo %var%”也执行成功了,它显示了字符“var”。但是两者之间没有建立起关系,没有达到我们的理想。
- ::解决的办法就是开启变量延迟,命令FOR必须先SET,然后ECHO,按规定办事,不能跳槽。
- ::具体参考后面案例5和案例9
- pause>nul
- setlocal EnableDelayedExpansion
- echo.
- echo 3、启用变量延迟之后——对比以下三个ECHO结果
- echo.
- for /f "tokens=1,2,3" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
- set var1=%%i
- set var2=%%j
- set var3=%%k
- echo %%i %%j %%k——成功
- echo %var1% %var2% %var3% ——失败
- echo !var1! !var2! !var3!——成功
- )
- ::开启变量延迟之后,原来的变量还可以使用。
- ::但用SET转换变量之后,变量不再使用百分号界定,而是用感叹号界定。这是许多新手很容易不注意的地方。
- ::为什么一定要把变量的百分号换成感叹号?I DON'T KNOW。或许是变量延迟喜欢标新立异吧,要不人家怎么知道它是变量延迟?~
- pause>nul
- setlocal EnableDelayedExpansion
- echo.
- echo 4、为什么要转换变量?——对比以下三个ECHO结果
- echo.
- for /f "tokens=1,2,3" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
- set var1=%%i
- set var2=%%j
- set var3=%%k
- echo %%%i:~4,3%——失败
- echo !%%i:~4,3!——失败
- echo !var1:~4,3!——成功
- )
- ::因为使用原来的变量“%%i”无法截取字符串,只好用SET转换变量。
- ::在FOR中,“%%i”经常失效,所以SET才了用武之地。
- pause>nul
- echo.
- echo 5、未启用变量延迟的情况下
- echo.
- set var=牛&echo 1 实际上:牛——%var%: 显示结果
- set var=猪&echo 3 实际上:猪——%var%:显示结果
- set var=羊&echo 2 实际上:羊——%var%:显示结果
- set var=马&echo 4 实际上:马——%var%:显示结果
- set var=人&echo 5 实际上:人——%var%:显示结果
- set var=人&&echo 6 实际上:人——%var%:显示结果
- echo 7 %var%:显示结果
- ::此案例证明了,批处理是“以行为处理”的模式。
- ::上一行设定变量,下一行使用变量。上下行是指,紧邻的上一行命令和下一行命令,不是相隔开的行。
- ::即使在使用“&”的情况下,其处理时间的先后顺序未改变,其结果也未变。
- ::“&”可以改变批处理的“上下行”的处理模式,将其转换成“前后句”的处理模式。
- ::但此处“&”失效了,因为ECHO的结果直接跳过了“&”前的“SET”,它使用的是上一句的“SET”。
- ::“&&”相当于“IF”为真的判断,当前一命令成功时执行后一命令,因此显示结果同前。
- ::需要注意的是,第一行的“%var%”在独立的BAT中,显示为空,但在这个批处理中,它显示的却是案例2的“中华人民共和国万岁 万岁 万万岁”。
- ::为什么“set var=%%i”在FOR中的下一行“echo %var%”没有成功,却跨越几十行代码在这里执行成功了呢?
- ::这个可能与FOR的机制有关,在FOR中,输出变量是统一由输入变量确定的,SET改变了输出变量,但在循环过程中被忽略了。
- ::具体参考案例6和9。
- pause>nul
- setlocal EnableDelayedExpansion
- echo.
- echo 6、启用变量延迟的情况下
- echo.
- set var=牛&echo 1 实际上:牛——!var!:显示结果
- set var=猪&echo 3 实际上:猪——!var!:显示结果
- set var=羊&echo 2 实际上:羊——!var!:显示结果
- set var=马&echo 4 实际上:马——!var!:显示结果
- set var=人&echo 5 实际上:人——!var!:显示结果
- set var=人&&echo 6 实际上:人——!var!:显示结果
- echo 7 !var!:显示结果
- ::开启变量延迟之后,“SET”和“&”都获得了执行的时间,ECHO在等待前一句的“SET”执行成功时才执行。这次它不可以跳级了。
- ::批处理的处理模式由“上下行”的模式转变为“前后句”的模式。
- ::变量延迟,其实应该这样理解,在遇到指定变量时,延迟原命令的执行时间,提前(预先、优先)处理涉及指定变量的命令,再按原来的时间顺序执行。
- pause>nul
- setlocal EnableDelayedExpansion
- echo.
- echo 7、处理字符串
- echo.
- for /f %%i in ("我十分喜欢批处理") do (
- set var=%%i
- for /l %%a in (0,1,10) do (
- set str=!var:~%%a,1!
- if defined str echo !str!
- )
- )
- ::此代码由两个FOR组成复合结构。“for /f ”用于解析“我十分喜欢批处理”,“for /l”用于输出数字。
- ::为什么需要数字?因为在截取字符(“set str=!var:~%%a,1!”)时需要界定字符的偏移量,而该偏移量是一串自然数,可以用“for /l”实现。
- ::按照批处理通常的处理模式,它会从第一行一直执行到最后一行,但是在两个FOR组合中,它的这个顺序被改变了。
- ::因为FOR的处理模式是,从集合中提取变量逐一执行,依此循环而止。但FOR中有FOR,它的顺序被第二次改变。FOR中还有SET,它的顺序被第三次改变。
- ::据前面案例所知,不启用变量延迟,变量只执行最后一个(一行)的变量设置,前面和中间的同一变量因为跨行而被跨跃过去,无法实现。
- ::整个过程比较啰嗦,不好解释,具体参考案例9。
- pause>nul
- echo.
- echo 8、setlocal与endlocal
- echo.
- set a=1
- set b=2
- rem 开始临时变量设置
- setlocal
- set a=3
- set b=4
- echo %a%
- echo %b%
- rem 结束临时变量设置
- endlocal
- echo %a%
- echo %b%
- ::借用“风行者 ”的代码。具体使用endlocal的情况不是很清楚,因为基本上没用到它。
- ::setlocal最多可以使用32次,也就是setlocal的最大递归数是32,使用endlocal来结束临时变量设置。
- pause>nul
- echo.
- echo 9、变量转换对比
- echo.
- set var=不怕中国城管来抓你,就怕菲律宾警察来救你!
- for /f "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
- set var=%%i
- set str=%%i
- set inf=%%i
- set opq=%%i&echo 一 %var% %str% %inf% %opq%
- set abc=芝加哥经济学派
- echo 二 %var% %str% %inf% %opq% %abc%
- )
- echo 三 %var% %str% %inf% %opq% %abc%
- ::原来有效的“set var=%%i”和“echo %var%”在FOR之中失效了。
- ::未启用变量延迟的FOR之中,上下行之间失去了直接关联,因此SET的变量被挂起。
- ::可能的情况是,FOR从集合中提取第一个变量“中华人民共和国万岁”,然后逐一执行DO后面括号里的每行命令。
- ::也就是说,此时的“set var=%%i”不是与它上下行的命令“echo %var%”产生关系,而是与集合内的字符串“中华人民共和国万岁”发生作用。
- ::DO后面的命令行并非自成一体的,它受到了FOR的控制,它的顺序被改变了。
- ::它们不是真正意义上的上下行关系,只是一种形式上的上下行关系。此时的变量延迟有点“拨乱反正”的意义。
- ::如案例中的“set abc=芝加哥经济学派”,在FOR中ECHO无效。启用变量延迟之后,变量设置被继续保留,在FOR进行一下循环的时候终于发生了作用。
- ::此案例告诫我们,在一个BAT中,应当尽量避免使用同一“变量名称”,以免造成前后混乱。
- ::我前段时间就因此吃亏,因为使用CALL,CALL同一命令时变量是相同的,在CALL前的变量设置延续到了CALL之后的变量之中,给我制造了许多麻烦。
- pause>nul
- setlocal EnableDelayedExpansion
- echo.
- echo 10、变量延迟中的变量变化
- echo.
- set var=不怕中国城管来抓你,就怕菲律宾警察来救你!
- for /f "tokens=*" %%i in ("中华人民共和国万岁 万岁 万万岁") do (
- set var=%%i
- set str=%%i
- set inf=%%i
- set inf=Verygood
- set opq=%%i&echo 一 1!var! 2!str! 3!inf! 4!opq!
- set abc=芝加哥经济学派
- echo 二 1!var! 2!str! 3!inf! 4!opq! 5!abc!
- )
- echo 三 1%var% 2%str% 3%inf% 4%opq% 5%abc%
- ::启用变量延迟之后,各个变量的设置都得到了保留,而之前变量的设置则被忽略了。
- pause>nul
- 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://bbs.bathome.net/) |
Powered by Discuz! 7.2 |