Blogn - 记录个人历史 Ver 3.0.0
http://www.bloggern.com
首页  留言本  注册  用户名: 密码:  
批处理:变量延迟setlocal enabledelayedexpansion
作者:iTT   3538字节   点击:44508   回复:1109   所属分类:
创建时间:2011-09-03 13:32:58   最后修改时间:2011-09-03 13:32:58  
变量延迟 setlocal EnableDelayedExpansion,一个让大多数新手头痛的问题,网上教程虽多,但多半都是看不懂的,里面的专业术语太多。以 cn-dos 联盟的willsort的这篇教程为例,(个人认为是解释的极具权威和专业的)
http://www.cn-dos.net/forum/viewthread.php?tid=20733&fpage=1&highlight=%E5%BB%B6%E8%BF%9F
在什么时候需要延迟变量,和该如何引用延迟变量,我想这才是大多数新手迫切想要知道的问题。耐心看完下面的内容,我想对你应该是有帮助的。

要想了解延迟变量,首先你要明白什么是“复合语句”

所谓“复合语句”就是指一对()里的所有命令。比如for的do后面
如:

for /f "delims=" %%i in (a.txt) do (
set var=%%i
echo %%i
set num=%%i
)

这里do后面的三句命令,在一对()里面,这就叫“复合语句”,当然不止for 还有if 等等。
如:

if "%var%"=="abc" (
echo ok
set lis=123
)
反正就是凡是()里的所有命令,就叫“复合语句”

另外:这也是复合语句 set abc=123&echo %abc%
没错,通过管道命令&连接起来的命令,也是复合语句。

好,了解了复合语句,现在开始讲延迟变量,也就说,在复合语句中才要使用延迟变量。
我们先不去理解什么叫“变量的扩展”这玩意叫法太专业,我到现在都不太明白,我们只要知道在什么时候需要使用延迟变量,如何才能正确提取到我们需要的变量就可以了,这才是我们的目的。

cmd在处理“复合语句”的时候,如果“复合语句”中用到了变量,会把变量的值当作复合语句之前变量的值来引用。如果在此之前变量没有被赋值,就把它当成空值。

呵呵,有点绕口。看个例子
例1:

@echo off
for /l %%i in (1 1 10) do (
set var=%%i
echo %var%
)
pause

运行上面的代码,显示什么?显示10个echo处于关闭状态。
按照逻辑,var的值应该依次是 1、2、3........10 才对啊!
这就是因为没有开启 延迟变量 的缘故,cmd把var的值当作复合语句之前的值来引用,
而再本例中,复合语句之前并没有给var定义,所以var的值是空的,所以会显示10个echo处于关闭状态。

再看例2:

@echo off
set var=abc
for /l %%i in (1 1 10) do (
set var=%%i
echo %var%
)
pause

运行上面的代码,会显示什么,大家应该知道了吧?
再看例3:

@echo off
set var=abc
for /l %%i in (1 1 5) do (
set var%%i=%%i
echo %var%
)
echo %var1% %var2% %var3% %var4% %var5%
pause

运行上面的代码后,复合语句中所赋的值全部显示出来了,这说明什么呢?
说明,在复合语句中,并不是没有给变量赋值,只是你若没有开启延迟变量,你就没法在复合语句中提取到它,要等复合语句运行完毕后,才能提取到。

变量的表示方法:两种: 1、%var% 2、!var!
第一种表示方法,大家都知道,第二种就是引用 延迟的变量。
在开启了延迟变量的情况下,如果在复合语句之外,用哪种方法表示都可以。
但是你若要在复合语句中引用复合语句即时得到的变量,就要用第二种方法。看例子
例4:

@echo off
setlocal EnableDelayedExpansion
set var = abc
for /l %%i in (1 1 10) do (
set var = %%i
echo %var%
echo !var!
)
pause

注意:例子中有两个echo 一个是显示 %var% 一个是显示 !var!
结果很明白了:%var% 显示的结果是复合语句之前变量var的值,而 !var! 显示的就是复合语句中即时得到的值。
再看例5

@echo off
setlocal EnableDelayedExpansion
for /l %%i in (1 1 5) do (
set var%%i=%%i
)
echo %var1% %var2% %var3% %var4% %var5%
echo !var1! !var2! !var3! !var4! !var5!
pause

说明在开启了延迟变量的情况下,且在复合语句之外,用两种方法都可以表示变量。
就说到这吧。以上的解释,完全是出于个人的理解,也是为方便非专业人士理解,解释肯定有错误的地方、就象学习英语时,为方便记忆,用汉字的读音来作解释一样。

另附一篇类似的文章,写的也不错,配合理解:

http://hi.baidu.com/0317439/blog/item/ffcde938de4766cbd4622560.html
附件:
评论:
来自: iTT   字节:3336  ID:18136  发贴时间:2011-09-03 13:33:28  原贴 
延迟变量全称"延迟环境变量扩展",要理解这个东西,我们还得先理解一下什么叫扩展!

CMD在解释我们的命令的时候,首先会读取命令行一条完整的命令,然后对其进行一些命令格式的匹配操作,看你所输入的命令格式是不是符合他的要求.

如果我们要在我们的命令中引用一些变量,那么我们如何让CMD在解释我们的命令时,能识别出这个变量呢?这时我们就可以在变量名字两边加一个%号,如%name%.当CMD在对读取我们的整行
命令进行格式匹配的时候,就会发现name这个字符两边加了%号,就不会把他当作普通字符处理,
而是会把他当作一个变量处理,变量名叫name!然后CMD就会找到变量名对应的值,用变量名的值替换掉这个变量名字(name),(如果变量名不存在值,就返回空值).再将这个替换好并且匹配的命令执行!这个替换值的过程,就叫做变量扩展,说白了就是把变量的名字,用他的值给替换掉后执行!也就是批处理如何识别一个变量的过程.


(注意:这里只是变量的扩展的意思,不是延迟环境变量扩展,要理解延迟环境变量扩展,必须先理解什么是变量的扩展) 也就是批处理如何识别一个变量的过程. ~_~

例如这个一个BAT
set var=test
echo %var%

CMD在读取到echo %var%这句命令后,就会进行匹配操作,它马上就发现var字符两边有%号,这时他就会把他当作一个变量处理,查看这个var变量名是不是有值,如果有就用他的值把变量名var给替换掉,这里我们的VAR在上一条命令set var=test中,给var赋值为test,所以他会用test把%var%这个变量名替换掉,替换后的结果就为echo test了.这些步骤都是CMD进行匹配操作的步骤,匹配完后,他再执行echo test这条语句,这时我们的CMD中就会echo出一个test了.


什么是环境变量扩展知道了,那什么是延迟环境变量扩展呢?

在理解环境变量扩展时,我们知道CMD在解释命令时,首先会把一条完整的命令进行读取,然后进行匹配操作,匹配时他会把命令里的变量用变量的值个替换掉,然后执行这个替换好的命令.
问题就出在"一条完整的命令",在BAT中,IF FOR这样的命令都可以加括号,将一些命令嵌套在里面执行.这样的话对于一条可以加扩号嵌其他命令的命令,他的完整格式就是
for %%i in (....)这样一个整体.此时,如果我们如果在括号里面嵌入一些设置变量值的命令,就会出现问题了!

看例子
@echo off
for /l %%i in (1,1,5) do (
set var=%%i
echo %var%
)

执行后会显示5个空行的错误提示!为什么?根据我们上面说的知识来理解


@echo off
set var=test
for /l %%i in (1,1,5) do (
set var=%%i
echo %var%
)

这个就会打印5个test了.


通过这两个例子,大家因该已经理解,如果只有环境变量扩展这个过程的话,如果我们在可以嵌套命令的命令中执行赋值操作时,会让我们的BAT出现给变量赋值的问题.
那么这个时候"延迟环境变量扩展",这个概念就被提出来了

在批处理中,我们可以用setloacl ENABLEDELAYEDEXPANSION这个命令来启用"延迟环境变量扩展"

在我们启用了"延迟环境变量扩展"后,当CMD在解释涵有嵌套格式的命令时,他会把嵌套的命令一条一条的先执行一次,然后再进行匹配操作,这样我们的赋值操作就会完成.并且再"延迟环境变量扩展"启用后,CMD会用!号来判断这是不是一个变量,如没启用来变量用%name%这样的格式判断,启用后就用!name!这样的格式判断了,这个符号我们需要注意!


例子:

@echo off
setlocal ENABLEDELAYEDEXPANSION
set var=test
for /l %%i in (1,1,5) do (
set var=%%i
echo !var!
)


这样大家因该明白什么是延迟环境变量扩展了吧.

再来一个例子

@echo off
set var=test & echo %test%
pause

这条命令放在一行,表示他是一条完整的命令,不启用"延迟环境变量扩展",就会出现上面的赋值错误!

改成这样
@echo off
setlocal ENABLEDELAYEDEXPANSION
set var=test & echo !var!
pause

很容易理解了吧!  
来自: 220.248.0.*   字节:24  ID:18401  发贴时间:2011-11-16 16:32:08  原贴 
博主写的非常好,赞一个!  
来自: 119.41.177.*   字节:20  ID:19051  发贴时间:2013-08-13 14:01:44  原贴 
解釋的非常清楚,感謝!  

本文允许匿名评论

发表评论:(最长不得超过128KB)
验证码:


您不能对本文发表评论。