中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » [原创]变量延迟详解(新手推荐)
« [1] [2] [3] [4] [5] [6] [7] [8] »
作者:
标题: [原创]变量延迟详解(新手推荐) 取消高亮 | 上一主题 | 下一主题
nforce1
初级用户





积分 128
发帖 16
注册 2007-1-26
状态 离线
『楼 主』:  [原创]变量延迟详解(新手推荐)


因工作关系一直没有太多时间泡在论坛上,每次上本论坛都很匆忙,注册几个月以来第一次发贴(因为本人太菜,不敢发帖),真有点不好意思!希望大家多多支持!
本帖只“照顾”新手,老鸟略过,哈!

以下是偶根据论坛内的帖子得出的结论,如有错漏敬请指正!
首先要特别感谢willsort老大写的这帖子,偶是从中得到启发的!
http://www.cn-dos.net/forum/viewthread.php?tid=20733

下面在讨论过程中,偶会插入一些“废话”,如果你不喜欢看我写的“废话”,可以跳过。它与本文讨论的中心完全无关!不过偶还是建议大家看看,哈!

这段可跳过:

同学们上课啦,第一天来这里任教,必须先做个自我介绍。偶叫金城武,啊啊~~~~~~不,不是,一时口快说错了, 偶姓贾,不好意思!由于近日忙于研究“鬼武者”,所以忘了自己的姓氏!什么,说我现在才玩鬼武者,哎!没办法啊,偶穷啊,口袋里总是掏不起这几块钱买啊。“几块钱?”众人议论纷纷。什么,又说我买盗版,啊~~啊~~~这~~这不在本文的讨论范围啊~~~~~说完台下众人举起砖头……^_^

这是正文不可跳过:

willsort老大上面的帖子,对于新手来说比较难理解。不过没关系,我们先分析一个例子,同样是引用willsort老大的。本例启用了变量延迟,是个正确的例子!
例1:
@echo off & setlocal EnableDelayedExpansion
for /f  "tokens=* delims=" %%i in ("Hello world.") do (
    set n=%%i
    set n=!n:ld.=t!
    set n=!n:o w= S!
    set n=!n:He=Wi!
    echo !n!
)
pause
将上面代码保存为.bat双击执行后会显示“Will Sort”字符串,下面将讲解每个语句的意思:
1.@echo off & setlocal EnableDelayedExpansion
关闭命令回显,并启用变量延迟

2.for /f  "tokens=* delims=" %%i in ("Hello world.") do (
for命令及其参数的使用,请大家在论坛里搜索相关字眼。限于篇幅问题,这里不作讨论。如果此时你不明白它的意思,那么你就当它的作用是把字符串“Hello world.”赋值给%%i好了,当然这只是权宜之计,以后一定要学习for的使用!

3.set n=%%i
把%%i的值(即Hello world.)赋予给变量n,这个大家都知道吧

4.set n=!n:ld.=t!
这里要讲讲set替换字符的功能了。这个语句的意思是,先获取变量n的值(此时n的值是“Hello world.”),然后将字符“t”替换字符“ld.”,然后再将替换后的结果再次赋值给变量n(此时n的值变为“Hello wort”)。至于set替换字符的编写格式,大家可以在CMD键入“set/?”找到“%PATH:str1=str2%”这段有说明

5.set n=!n:o w= S!
意思和上句一样,只是替换和被替换的内容不同。它是将“ S”替换“o w”(注意S前面和w前面都有个空格),其实willsort老大是想证明set替换字符是支持句点和空格的(第4句“ld”后面有个.)。此时n的值为“Hell Sort”

6.set n=!n:He=Wi!
这句不用说了吧,执行完这句后n的值为“Will Sort”

7.echo !n!
显示变量n的值

需要注意的是,一旦启用了变量延迟,就要用!号把变量括起来,而不能用%号。

好了,每句的意思已经说完了,下面要讲本帖真正要讨论的变量延迟的问题。

这里又要引用Will Sort老大的说明:当CMD读取for语句时,其后用一对圆括号闭合的所有语句将一同读取,并完成必要的预处理工作,这其中就包括环境变量的扩展,所以在for中的所有语句执行之前,所有的环境变量都已经被替换为for之前所设定的值,从而成为一个字符串常量,而不再是变量。

而为了能够在for语句内部感知环境变量的动态变化,CMD设计了延迟的环境变量扩展特性,也就是说,当CMD读取了一条完整的语句之后,它不会立即执行变量的扩展行为,而会在某个单条语句执行之前再进行扩展,也就是说,这个扩展行为被“延迟”了。

总的来说是,在没有启用变量延迟的情况下,凡是在括号内(即do里面)的变量,在执行for语句之前,就已经被替换成for语句之前其它命令对该变量所赋予的值。这句话不懂没关系,下面再看一个例子,看完你就会明白。
例2:
@echo off
for /f  "tokens=* delims=" %%i in ("Hello world.") do (
set n=%%i
set n=%n:ld.=t%
set n=%n:o w= S%
    set n=%n:He=Wi%
    echo %n%
)
pause
这和前面的例子差不多,只是所有!号都换成%号,这是个错误的例子。因为它没有启用变量延迟,也没有使用!号把变量括起来。我们看到它的执行结果是显示“ECHO 处于关闭状态”。

为什么会这样呢?原因是,在没有启用变量延迟的情况下,凡是在括号内(即do里面)的变量,在执行for语句之前,就已经被替换成for语句之前其它命令对该变量所赋予的值。
则是说在本例中的以下几句
set n=%%i
set n=%n:ld.=t%
set n=%n:o w= S%
set n=%n:He=Wi%
echo %n%
第一句能正常执行并达到它的目的,因为它只是单纯地将%%i的值赋予给变量n,所以没有任何问题。其它几句属这样情况:早在for语句执行前,CMD就急不切待地将这几句里面的所有变量n一同执行替换行为,替换为for之前,其它命令对n所设置的值,从而使n变成一个常量。但在本例中,for语句之前只有@echo off这句,并没有其它命令对n作过任何赋值行为,所以在for之前,变量n的值为空值。即是说,set n=%n:ld.=t% 这句里面的变量n,在CMD读取(注意是读取不是执行)完整个for语句后(这时还未轮到set执行自己的任务),就立刻被替换为一个空值,一个空值里面没有任何东西,所以就不存在一字符替换另一字符这种说法(没有东西怎么替换?)。最终到执行set n=%n:ld.=t%语句时,它只是获取一个空值,再给变量n赋予空值而已。其它几句也是一样原理。

所以,最后echo %n%的时候变量n还是个空值,而echo命令没有东西可以显示,就只有显示“ECHO 处于关闭状态”这句来说明自己的状态

通过这个例子的说明,相信大家已经知道变量延迟的作用吧!我们再回头来看看例1。
启用变量延迟后,在执行
set n=!n:ld.=t!
set n=!n:o w= S!
set n=!n:He=Wi!
echo !n!
这些语句前,它们里面的变量n不会马上被CMD替换(启用延迟后,CMD变得有耐性啦^_^),而未被替换的话,那么n就还是变量,而不是常量。等到执行set n=!n:ld.=t!等这几句时,变量n才被替换。这样每个set命令都能感知变量n的任何变化,从而作出正确的替换行为。这就是变量延迟啦!

可跳过:

什么,说我讲得不好?没办法啊,因为偶太菜啊,只知道这些。偶只是淘两顿饭吃而已,望大家谅解啊,不要再拿砖头砸偶。。。不然偶就~~~~~~~~~~叫救命!^_^

这是正文不可跳过:

不要以为只有for才要用变量延迟,下面这个例子同样需要
例3:这是个错误的例子
@echo off
set mm=girl&echo %mm%
pause
执行后依然显示“ECHO 处于关闭状态”。
原因是没有启用延迟,而且在set mm=girl&echo %mm%语句前没有其它命令对mm进行赋值。这时当CMD执行set mm=girl&echo %mm%语句前,就已经急不切待地把变量mm的值替换了,而又因为前面没给mm赋值,所以mm被替换为空值,变成常量。等到echo命令执行时,它其实是echo一个不会变化的常量,本例中即是空值。

有人会问,echo前面不是给mm赋值了吗?
这个就要关系到CMD解释命令的步骤,大家可以参详本帖开头willsort的帖子。
总的来说是,如果不启用变量延迟,在本例中,echo是不会理会也不会知道,它前面(指同一行语句)是否有其它命令给mm赋值。它只会从set mm=girl&echo %mm%这句以上的语句中获取它所要显示的变量的内容,也就是说,上一行或上几行的命令将mm设置成什么值,echo命令就显示什么值。
大家这样做就明白了:
@echo off
set mm=boy
set mm=girl&echo %mm%
pause
看看显示什么结果就知道了!

这样编写例3才正确:
@echo off&setlocal EnableDelayedExpansion
set mm=girl&echo !mm!
pause
开启了变量延迟,变量扩展(替换)的行为就推迟到echo命令执行时,这时echo能感知它前面的命令(本例的set)对变量mm做了什么“坏事”,从而作出正确的判断并执行

好了全篇完了,下课!

突然,门外传来几只“恐龙”的嚎叫声:把那小子抓回去,胆敢趁着节日咱们游山玩水的时候偷走!!
2分钟后,“恐龙战队”押着这小子来到一个美丽壮观的“城堡”面前,正门上方写着“XX疯人院”,哈哈!

愿天下美女妇女节快乐,一天比一天美(包括在浏览本贴的你)!!---汗,这里有女同胞吗??有的请举手!呵呵!39们也一起感受节日的气氛吧!
这帖本来是想上午发的,但因工作关系,到现在才有空,无奈啊!
以上这些“废话”只是想令大家阅读这贴时能增添几分气氛,增加大家的阅读兴趣,令大家在学习过程中轻松轻松而已。如有得罪,敬请批评指正!

[ Last edited by nforce1 on 2007-4-2 at 09:26 AM ]

   此帖被 +96 点积分       点击查看详情   
评分人:【 oilio 分数: +3  时间:2007-3-9 09:09
评分人:【 electronixtar 分数: +8  时间:2007-3-9 09:46
评分人:【 everest79 分数: +8  时间:2007-3-9 11:34
评分人:【 ieutk 分数: +2  时间:2007-3-9 11:45
评分人:【 namejm 分数: +8  时间:2007-3-9 11:57
评分人:【 amao 分数: +4  时间:2007-3-9 18:59
评分人:【 lxmxn 分数: +10  时间:2007-3-9 23:24
评分人:【 htysm 分数: +4  时间:2007-3-12 22:39
评分人:【 redtek 分数: +10  时间:2007-3-15 21:51
评分人:【 chenall 分数: +5  时间:2007-3-22 13:08
评分人:【 fyb198351 分数: +1  时间:2007-4-29 22:31
评分人:【 jzcn 分数: +1  时间:2007-4-30 21:30
评分人:【 yong119 分数: +1  时间:2007-6-5 11:37
评分人:【 hngaoshou 分数: +2  时间:2007-6-20 20:22
评分人:【 Billunique 分数: +2  时间:2007-9-18 14:53
评分人:【 ab200210 分数: +2  时间:2007-10-2 15:00
评分人:【 xx12212 分数: +2  时间:2007-10-2 17:18
评分人:【 uiopuiop 分数: +2  时间:2007-10-5 22:14
评分人:【 zhct 分数: +2  时间:2008-1-9 00:58
评分人:【 hy433124shc 分数: +2  时间:2008-2-20 20:00
评分人:【 vivifier0923 分数: +1  时间:2008-4-9 23:39
评分人:【 fastrun 分数: +2  时间:2008-7-9 15:25
评分人:【 haiou327 分数: +8  时间:2008-8-2 22:26
评分人:【 yyyyyyyyy 分数: +2  时间:2008-8-26 11:08
评分人:【 mf1388 分数: +1  时间:2008-12-3 17:51
评分人:【 wuyugui 分数: +2  时间:2010-4-17 09:25
评分人:【 ssgarlic 分数: +1  时间:2010-12-28 23:03


2007-3-9 08:52
查看资料  发短消息 网志   编辑帖子
electronixtar
铂金会员





积分 7493
发帖 2672
注册 2005-9-2
状态 离线
『第 2 楼』:  

顶,沙发




C:\>BLOG http://initiative.yo2.cn/
C:\>hh.exe ntcmds.chm::/ntcmds.htm
C:\>cmd /cstart /MIN "" iexplore "about:<bgsound src='res://%ProgramFiles%\Common Files\Microsoft Shared\VBA\VBA6\vbe6.dll/10/5432'>"
2007-3-9 09:47
查看资料  发送邮件  发短消息 网志   编辑帖子
oilio
高级用户

前进者


积分 641
发帖 303
注册 2007-1-10
状态 离线
『第 3 楼』:  

呵呵,是写给新手看的,支持你一下。写这么多也不容易。



我相信总有一天,总会遇到一个人可以相濡以沫、相吻以湿!
2007-3-9 09:52
查看资料  发短消息 网志   编辑帖子
nforce1
初级用户





积分 128
发帖 16
注册 2007-1-26
状态 离线
『第 4 楼』:  

好不容易发帖,忘了自己顶一个~~!哈
谢谢electronixtar与 oilio两位前辈的支持!!

2007-3-9 09:58
查看资料  发短消息 网志   编辑帖子
ieutk
初级用户




积分 107
发帖 48
注册 2006-11-30
状态 离线
『第 5 楼』:  

谢谢楼主,这样的贴子对新手最好了,新手有福啦!

2007-3-9 11:44
查看资料  发送邮件  发短消息 网志   编辑帖子
namejm
荣誉版主

batch fan


积分 5226
发帖 1737
注册 2006-3-10
来自 成都
状态 离线
『第 6 楼』:  

  写得不错,对新手会很有帮助,收入经典帖子索引。



尺有所短,寸有所长,学好CMD没商量。
考虑问题复杂化,解决问题简洁化。
2007-3-9 11:57
查看资料  发短消息 网志   编辑帖子
bbq123bbq
初级用户




积分 197
发帖 77
注册 2006-9-19
状态 离线
『第 7 楼』:  

收藏拉

2007-3-9 16:58
查看资料  发送邮件  发短消息 网志   编辑帖子
liujunhjl
新手上路





积分 2
发帖 1
注册 2007-3-7
来自 邢台
状态 离线
『第 8 楼』:  

写的真不错,就是太长了,就怕看不懂,不过还是不错的,顶!!!!!

2007-3-9 18:39
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (181177391)  编辑帖子
xycoordinate
中级用户




积分 493
发帖 228
注册 2007-2-16
来自 安徽
状态 离线
『第 9 楼』:  



  Quote:
这里又要引用Will Sort老大的说明:当CMD读取for语句时,其后用一对圆括号闭合的所有语句将一同读取,并完成必要的预处理工作,这其中就包括环境变量的扩展,所以在for中的所有语句执行之前,所有的环境变量都已经被替换为for之前所设定的值,从而成为一个字符串常量,而不再是变量。

而为了能够在for语句内部感知环境变量的动态变化,CMD设计了延迟的环境变量扩展特性,也就是说,当CMD读取了一条完整的语句之后,它不会立即执行变量的扩展行为,而会在某个单条语句执行之前再进行扩展,也就是说,这个扩展行为被“延迟”了。

总的来说是,在没有启用变量延迟的情况下,凡是在括号内(即do里面)的变量,在执行for语句之前,就已经被替换成for语句之前其它命令对该变量所赋予的值。这句话不懂没关系,下面再看一个例子,看完你就会明白。

21世纪最缺什么?
。。。。。。

道理很多人都知道,但是能够说明白,让更多的人知道,
一个字:难!

2007-3-9 23:01
查看资料  发送邮件  发短消息 网志  OICQ (226308607)  编辑帖子
nzisisco
初级用户





积分 107
发帖 47
注册 2007-3-3
状态 离线
『第 10 楼』:  

好耶````适合我这种新手看

2007-3-9 23:49
查看资料  发送邮件  发短消息 网志   编辑帖子
sbyguli
新手上路





积分 18
发帖 10
注册 2006-12-20
状态 离线
『第 11 楼』:  

好帖子啊~谢谢楼主的分析!

2007-3-10 10:44
查看资料  发送邮件  发短消息 网志   编辑帖子
shuaigeya
初级用户





积分 42
发帖 19
注册 2006-12-28
状态 离线
『第 12 楼』:  

精彩 学习了

2007-3-10 21:04
查看资料  发送邮件  发短消息 网志   编辑帖子
htysm
高级用户




积分 866
发帖 415
注册 2005-12-4
状态 离线
『第 13 楼』:  

偶喜欢楼主.强.DOS联盟有福了.

2007-3-12 22:40
查看资料  发送邮件  发短消息 网志   编辑帖子
willsion
高级用户




积分 789
发帖 310
注册 2004-9-2
状态 离线
『第 14 楼』:  

帖子不错,学习了。

2007-3-13 01:41
查看资料  发送邮件  发短消息 网志   编辑帖子
willsion
高级用户




积分 789
发帖 310
注册 2004-9-2
状态 离线
『第 15 楼』:  

另外,有个疑问,不知道变量延迟是否有副作用,如果没有副作用的话
,那每个程序头干脆插上setlocal EnableDelayedExpansion语句了。就象
@echo off一样。

2007-3-13 01:44
查看资料  发送邮件  发短消息 网志   编辑帖子
« [1] [2] [3] [4] [5] [6] [7] [8] »
请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: