![]() |
中国DOS联盟-- 联合DOS 推动DOS 发展DOS --联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum |
| 游客 | 登录 | 注册 | 会员 | 搜索 | 中国DOS联盟 |
|
中国DOS联盟论坛 现在时间是 2026-08-12 01:43 |
共 47,811 主题排行 / 349,897 发帖 / 今日 0 篇 / 48,256 会员排行 |
| DOS批处理 & 脚本技术(批处理室) » [原创]变量扩展及call命令的“变量延迟”原理详析 |
| 可打印版本 2,281 / 5 |
| 第1楼 q8249014 | 发表于 2009-10-14 17:22 |
| 初级用户 发帖 45 积分 175 | |
|
[原创]变量扩展及call命令的“变量延迟”原理详析 批处理学习帖① —— 变量扩展及call命令的“变量延迟”原理详析
前言: 本系列教程适合有一定批处理基础的同学学习,如果我下文的内容你看不懂,说明你的基 础较差,建议你在论坛潜水一段时间,翻看老贴并仔细实践,回来后相信你一定会看懂的。 下面我们就一起来系统的学习一下批处理的变量扩展和call命令的“变量延迟” 注意:如果没有特别说明,批处理学习帖中讲解的内容都是在批处理环境中的 一、变量扩展 变量是怎样进行扩展的呢?
请你先执行一下代码1
下面就用代码1中的最后一句代码来给同学们分析一下(echo.%%%var%%%%) (1)变量扩展:因为“var”的左边有三个百分号,3为奇数,所以将“%var%”替换为“test” 那么这时“%%%var%%%%”变为“%%test%%%” (2)脱百分号:因为这时“test”左侧有两个百分号,所以直接脱掉一半, 而右侧有三个百分号所以脱掉(3÷2+0.5)2个百分号,所以最后结果就变为“%test%” (变量扩展的“替换步骤”)中叙述的可能有些抽象,但是大家实践下再结合“(echo.%%%var%%%%)”的分析应该就明白了 看到这里同学们应该能明白环境变量扩展的过程了,但是有一点必须向同学们说明白,以上所说的“替换步骤” 只是为了让新同学能够更好的理解环境变量扩展的过程,而在批处理中命令解释器是不会按照上面的那一套规 则来扩展变量的,但是同学们也不用担心,虽然处理的方式不同但是结果都是一样的。 下面将从命令解释器解释“%”“变量标识符”的角度来给同学们讲解一下变量扩展的过程 “%”字符在批处理中被解释为“变量标识符”,那么在批处理中“%”就属于一个特殊符号了,从预处理的 角度来讲,命令解释器在读取完毕一条完整的批处理语句后(“%var%”)首先对变量进行扩展,那么在这 个时候语句中所有的“%”都被当作“变量标识符”解释了,变量扩展完毕后所有的“%”也就不存在了,然 而在这个时候命令解释器还没有对“^”转义字符进行解析,那么我要输出“%”怎么办?我们只想输出“%var%” 而不想让它被解释怎么办?那就要想办法取消“%”的特殊性,让命令解释器不对它进行处理,那么在这 个时候自然就需要一个字符来对“%”进行转义处理,这个字符是什么呢?其实它还是“%”本身,所以 ,“%”字符在批处理中的第二个身份就是“转义符”。注意:“%”只会对“%”进行转义,有别与“^”。 下面还是用代码1中的“echo.%%%var%%%%”来分析一下 1.echo.后面的第一个“%”对第二个“%”进行转义处理,这时第二个“%”变为普通字符,命令解释 器不在对它进行解释,而第一个“%”被命令解释器解释为“转义符”,所以不存在了。 2.echo.后面的第三个“%”和var还有第四个“%”组成一个完整的变量引用,所以“var”被替换为 “test”,对“var”进行引用的两个“%”被命令解释器解释为“变量标识符”,所以不存在了。 3.同echo.后面的第五个“%”对第六个“%”进行转义处理,这时第六个“%”变为普通字符,命 令解器不在对它进行解释,这时第五个“%”就不存在了。 4.最后一个也就是第七个“%”,命令解释器将它解释为“变量标识符”,所以不存在了 5.这时候对“%”的处理全部进行完毕,我们将前四步的结果组合起来,% test %,最后 的结果就变为:%test% 根据以上的分析过程,可以看出当两个“%”在一起的时候,前一个“%”被命令解释器解释为“转义符”,后一个 “%”被前一个“%”转义成普通字符了,并遵循从左向右的原则。 不知道上面解释大家能不能看懂,即使看不懂也没关系,只要 (变量扩展的“替换步骤”) 中的内容能明白就可以了, 因为 (变量扩展的“替换步骤”) 容易理解一些,所以下文及以后的学习帖中任然采用“替换步骤”来进行讲解。 (变量扩展的“替换步骤”)中的步骤是通过变量扩展的结果而总结出来的规律,新同学更容易理解一些,但要从本质 上理解原因,还是要理解上面的分析,不然你就会问,为什么奇数扩展而偶数不扩展,呵呵。 注:由于“%”的双重特性,预处理后自然有一些“%”不存在了,所以也有人叫它“逃逸字符”或者“脱字符”。 “原创文章,转帖请注明出处cn-dos&q8249014哦” 二、call命令的“变量延迟” 我们知道命令在执行之前 命令解释器会对命令语句进行一些必要的解释处理,这个过程我们称 之为“预处理工作”,第一段中所讲的“变量扩展”就属于预处理工作的一部分,下面先看一下 和预处理有关的一些知识。 __________________________________________________________________________ 在这里首先给同学们简要的说明一下什么是“预处理工作” 就我个人理解预处理就是命令解释器对命令进行解释、匹配处理的一个过程,它进行于命令执行前 那么“预处理工作”到底做了些什么呢? (1)首先对使用“%”引用的变量进行扩展 (2)对命令中的字符进行匹配解释,如把“&”匹配为命令连接符 Rem (3)如果包含if(for)命令,则对if(for)命令的格式进行检查 Rem (4)如果包含if(for)命令,待if(for)命令语句中的所有变量都扩展完毕后进行条件处理, 然后把满足条件的命令语句提交给该命令主体执行 (3)…………等待你的挖掘 (4)进行延迟变量的扩展(会处理转义字符“^”) (5)预处理工作进行完毕后,把命令语句提交给命令主体执行 注:以上使用Rem注释的内容,不要求新同学们完全理解 批处理经验丰富的朋友应该能明白__________________________________________________________________________ 为了便于同学们更好的理解下文中的两段代码,这里引用本论坛中willsort的一篇文章
请你先执行一下代码2 为什么代码2执行后的结果是“test”,而不是“cn-dos” 呢? 分析: ________________________________________________________________________ 这是因为cmd读取for这一完整语句后就进行必要的预处理工作,所有能被扩展的变量都已被替换 为之前设定的值了,所以在代码2中执行到“echo.%var%”时实际执行的命令是“echo.test”。 (换句话说,在还没有执行“set "var=cn-dos"”的时候“%var%”就等于“test”了) ________________________________________________________________________
请你先执行一下代码3 用了call命令后变量扩展和不用call有什么区别呢? (test&cn-dos) 代码3仅多了一个call,为什么结果就和代码2不一样呢?代码3为什么可以显示“cn-dos” 呢? 用call命令是如何实现“变量延迟”效果的呢? 分析: _______________________________________________________________________________ 因为call命令在处理命令语句时默认也会对变量进行扩展,所以用了call命令后便会多一次“替换步骤” (一):读取完毕一条完整语句后,命令解释器进行预处理时对环境变量进行扩展的步骤 1.变量扩展:“call echo.%%var%%”,因为“var”左边有两个百分号,所以变量不被替换 2.脱百分号:因为“var”两侧的百分号都是偶数个,所以两侧的百分号都脱掉一半变为“%var%” (二):命令语句提交给call命令后,call命令内部对环境变量进行扩展的步骤 1.变量扩展:这时已经执行“set "var=cn-dos"”,var的值已经被定义为“cn-dos”,那么“%var%”将被 扩展为“cn-dos” 2.脱百分号:没有百分号所以不拖啦,所以结果就是“cn-dos” 注:以上的“替换步骤”和第一段中的 (变量扩展的“替换步骤”) 是一样的 _______________________________________________________________________________ 以上使用call来进行变量延迟扩展的主要思路是: (1)在变量左侧使用偶数个百分号对变量进行引用,以便在预处理时变量不被扩展 (2)命令语句提交给call命令后,call命令在处理命令语句时会再次对变量进行扩展,那么就达到了延迟扩展的目的 这里请新同学结合上面的分析 比较一下代码2和3的结果并弄懂原因 体会一下call命令的“变量延迟”的运用 这样有助于第三段实例演示的学习 “原创文章,转帖请注明出处cn-dos&q8249014哦” 三、实例演示 代码4是论坛中“terse”写的一段10进制转为16进制的代码,代码5是我进行“修整”后的一段代码 这段代码也是我所见过最短的一段10进制转为16进制的代码 代码4中变量截取那一段因为不能直接使用 “set h=!hx:~!n!,1!!h!”或“set h=%hx:~!n!,1%!h!”进行截取,所以他使用for把变量 “!n!”传递给%%i,然后在进行变量替换“set h=!hx:~%%i,1!!h!”。 而我“修整”的代码5中则充分利用了call命令的“变量延迟”,即:“call set h=%%hx:~!n!,1%%!h!” 这里只是讨论一下批处理技巧没有其他的意识,“terse”的代码还是很好的哟,呵呵 以上代码4和5同学们进行一下比较,再体会一下call“变量延迟”的运用,最好能完全读懂每一句代码的意识。 作业:弄懂代码5“echo.%str% 的十六进制为:0x!h!”中“str”的值为什么是你输入的数字而不是0 “call set h=%%hx:~!n!,1%%!h!”自行分析一下这一句的执行过程 四、总结 这里给同学们补充一下开启延迟环境变量后使用“!”引用的变量的“替换步骤” (1)读取完命令语句后,cmd不会立即扩展使用“!”引用的变量, 使用“%”引用的变量任然使用第一段(变量扩展的“替换步骤”)中的规则进行扩展 (2)进行预处理匹配工作 (3)在命令执行前对使用“!”引用的变量进行扩展 也就是说开启变量延迟后使用“!”引用的变量将在读取到该句后执行该句前的最后一步才进行扩展 扩展的规则是:先检查变量是否被定义,是则扩展为其值,否则用空串替换,另外所有多余的“!”都 会用空串进行替换(被解释为“变量标识符”)。如果是在cmd命令行中执行多余的“!”则不会被替换。 在批处理学习帖③中给同学们总结一下开启变量延迟后使用“!”引用的变量扩展时怎样处理转义“^”字符 “%”和“!”引用的变量扩展的区别: 在读取完毕一个单条语句或复合语句后,语句中所有使用“%”引用的变量将会被扩展 在读取完毕一个单条语句或复合语句后,语句中所有使用“!”引用的变量不会被扩展, 而是在读取完该语句后执行该语句前的最后一步在进行扩展 以上所说的“变量扩展”其实就是“变量替换”的意识,这样解释同学们可能容易理解一些 好这一课到这里就结束了 如果文中有什么不妥之处,敬请坛友们斧正哦 “原创文章,转帖请注明出处cn-dos&q8249014哦” 2009年12月1日 修订 [ Last edited by q8249014 on 2010-2-4 at 16:52 ] |
|
| 第2楼 hgj9999 | 发表于 2009-11-30 10:26 |
| 新手上路 发帖 2 积分 2 | |
|
这么好的帖子怎么没人回呢
对call的理解我还很初级啊,要继续学习 |
|
| 第3楼 heng520 | 发表于 2009-11-30 20:08 |
| 初级用户 发帖 16 积分 29 | |
|
好祥细,很不错
还得继续学习啊。。 |
|
| 第4楼 wzc6063724 | 发表于 2010-08-17 12:24 |
| 新手上路 发帖 8 积分 11 | |
|
学习了,这方面我一直不懂,今天受教了
![]() |
|
| 第5楼 491321720xxw | 发表于 2010-10-03 18:18 |
| 新手上路 发帖 2 积分 3 来自 四川 | |
|
好好,有多懂老!!!!!!!!
|
|
| 第6楼 hfg1977 | 发表于 2010-10-05 10:41 |
| 新手上路 发帖 1 积分 1 | |
|
1.学习了call 及"!"延时
2.获得了更好的D2H方法. 谢谢楼主. |
|
|
[ 联系联盟系统管理团队 -
中国DOS联盟 -
标准版 ] Sponsored by ifanr Inc | © 2001–2023 |