标题: 批处理变量延迟详解 [打印本页]
作者: Batcher 时间: 2008-12-25 14:39 标题: 批处理变量延迟详解
因工作关系一直没有太多时间泡在论坛上,每次上本论坛都很匆忙,注册几个月以来第一次发贴(因为本人太菜,不敢发帖),真有点不好意思!希望大家多多支持!
本帖只“照顾”新手,老鸟略过,哈!
以下是偶根据论坛内的帖子得出的结论,如有错漏敬请指正!
首先要特别感谢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 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们也一起感受节日的气氛吧!
这帖本来是想上午发的,但因工作关系,到现在才有空,无奈啊!
以上这些“废话”只是想令大家阅读这贴时能增添几分气氛,增加大家的阅读兴趣,令大家在学习过程中轻松轻松而已。如有得罪,敬请批评指正!
原文地址:http://www.cn-dos.net/forum/viewthread.php?tid=28273
作者: xujin1402008 时间: 2008-12-28 15:18
好长的贴啊,要仔细研究下~
作者: ahongguo 时间: 2008-12-28 16:14
个人见解,如有冒犯请间量(俺是新手) 这种延迟好象作用不大
对于你上所举例子,好象与for set 读写机智有关呢 如:
A)@echo off
for /f "tokens=* delims=" %%i in ("Hello world.") do (
set n=%%i
set n=%n:ld.=t%
set n=%n w= S%
set n=%n:He=Wi%
echo %n%
)
pause
将 echo %n% 弄到那括号外面,就可以显示了
B)
@echo off
set mm=boy
set mm=girl&
pause
将后面的 echo %mm% 另起一行 同样能达到那种所要目的
作者: yslyxqysl 时间: 2008-12-28 16:35
- @echo off&setlocal EnableDelayedExpansion
- set a=2
- set b2=x
- if !b%a%!==x echo yes
复制代码
这个批处理你不开延迟吗?
作者: Batcher 时间: 2008-12-28 19:58 标题: 回复 3楼 的帖子
变量延迟扩展的作用很大,建议多看几遍相关教程。
作者: lzwudi 时间: 2009-1-4 11:49
非常理解您的心意...谢谢.但是给个意见.请勿见怪!
个人认为您的意图很明确.但是文章不是很通熟易懂......
就像你提到的"willsort老大"...说"其粗劣的翻译水平"......
他的语言表达能力也不怎么理想....
还有像"ahongguo"所说的一样...您举的几个例子好象起不到启发的作用....
在我这样的新手看来.变量延迟的意义懂了点.但是按照您的例子学习..以后应用是点问题
这样的例子是不需要用变量延迟就可以达到的..所以用它来举例有点迷惘
作者: Batcher 时间: 2009-1-4 13:07 标题: 回复 6楼 的帖子
//就像你提到的"willsort老大"...说"其粗劣的翻译水平"......
不知这位仁兄在哪里看到有人说“willsort老大粗劣的翻译水平”?
//他的语言表达能力也不怎么理想....
关于变量延迟扩展的教程,本版有好几篇,建议结合起来看。
//还有像"ahongguo"所说的一样...您举的几个例子好象起不到启发的作用....
变量延迟扩展绝对不是看几个例子就能掌握的,需要今后自己写代码的过程中慢慢体会。
//在我这样的新手看来.变量延迟的意义懂了点.但是按照您的例子学习..以后应用是点问题
哪里有问题就问哪里。能发现自己的问题所在也是一直进步。
//这样的例子是不需要用变量延迟就可以达到的..所以用它来举例有点迷惘
如果你是说3楼的帖子,建议重新看几遍教程。因为3楼的兄弟根本没有理解变量延迟扩展应该用在什么地方。
作者: cmbatd 时间: 2009-1-4 17:00 标题: 回复 4楼 的帖子
郁闷~~
刚才的回复居然没有发上去
换行就行了,不过楼主讲的貌似不是为个主题
我是新手,刚加进来的
看了很受益!!!
作者: nanoking 时间: 2009-1-5 03:23
似乎只要引用了!var!,都要加变量延迟。
作者: zjw767676 时间: 2009-1-23 13:49
多看几个教程,反复练习,会有懂的一天的
作者: jackelijie135 时间: 2009-3-15 16:29
有点收获,O(∩_∩)O哈哈~
作者: januapr 时间: 2009-8-8 05:13
这是一篇不错的文章,看了几次受益不浅!
作者: fuwei880306 时间: 2009-12-16 21:02
越看越觉得玄了..似懂非懂的样子
作者: changedirectory 时间: 2013-12-11 15:10
回复 3# ahongguo
如果把echo %n%放到外面,显示的结果就是He=Wi
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |