批处理学习帖① —— 变量扩展及call命令的“变量延迟”原理详析
前言:
本系列教程适合有一定批处理基础的同学学习,如果我下文的内容你看不懂,说明你的基
础较差,建议你在论坛潜水一段时间,翻看老贴并仔细实践,回来后相信你一定会看懂的。
下面我们就一起来系统的学习一下批处理的变量扩展和call命令的“变量延迟”
注意:如果没有特别说明,批处理学习帖中讲解的内容都是在批处理环境中的
一、变量扩展
变量是怎样进行扩展的呢?
@echo off
:: 代码1
set "var=test"
echo.%var%
echo.%%var%
echo.%%var%%
echo.%%%var%%%
echo.%%%var%%%%
pause
test
%var
%var%
%test%
%test%
请按任意键继续. . .
请你先执行一下代码1
(变量扩展的“替换步骤”)
1.变量扩展
(1)当cmd读取到使用“%”引用的变量语句后,首先检查“var”左边“%”的数量是否为奇数,
是则替换“%var%”为变量的值,偶数则不进行替换;如果变量未被定义则用空串替换。
2.脱百分号
(1)当“%var%”被替换为变量的值后,那么两边的百分号自然都会减少一个
(2)如果单侧百分号的数量是偶数,那么直接将百分号(%)脱掉一半
如果单侧百分号的数量是奇数,那么会脱掉百分号数量的一半+0.5
如果没有百分号就不脱啦
下面就用代码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的一篇文章
文中仅做了一些补充修改,使解释更为准确,方便大家参阅
关于环境变量延迟扩展,使用set /?可以查看到部分说明,不过考虑到其粗劣的翻译水平,建议在查看之
前,首先使用chcp 437切换为英文显示状态,在查看原英文说明。鉴于文中已说得十分详尽,并且有数个代码示
例,应该不难理解。在此仅略作一些补充。
在许多可见的官方文档中,都使用一对百分号闭合环境变量以完成对其值的替换,这个过程称之为“扩展
(expansion)”,这其实是一个第一方的概念,是从命令解释器的角度进行称谓的,而从我们使用者的角度来
看,则可以将它看作是引用(Reference)、调用(Call)或者获取(Get)。
命令解释器扩展环境变量的过程大致如下:首先读取命令行的一条完整语句,(命令被解释执行之前,会
进行一些预处理工作。)然后对其中使用百分号闭合的字符串进行匹配,如果在环境空间中找到了与字符串相匹
配的环境变量,则用其值替换掉原字符串及百分号本身,如果未得到匹配,则用一个空串替换。这个过程就是环
境变量的“扩展”,它属于命令行的预处理范畴。
一条“完整的语句”,在NT的命令解释器CMD中被解释为“for、if else、()”等含有语句块的语句和用
“&、|、&&、||”等连接起来的复合语句。
因此,当CMD读取for语句时,其后用一对圆扩号闭合的所有语句将一同被读取,并完成必要的预处理工作
,这其中就包括环境变量的扩展,所以在for中的所有语句执行之前,所有的环境变量都已经被替换为for之前所
设定的值了,从而成为一个字符串常量,而不再是变量。无论在for中将那些环境变量如何修改,真正受到影响
的只是环境变量空间,而非for语句内部。
为了能够在for语句内部感知环境变量的动态变化,CMD设计了延迟环境变量扩展的特性,而为了扩展时与
使用百分号闭合的环境变量进行区分,开启延迟环境变量扩展后要使变量延迟扩展应使用英文感叹号闭合环境变
量。也就是说,当CMD读取了一条完整的语句之后,它不会立即扩展使用英文感叹号闭合的环境变量,而是在某
个单条语句执行之前再进行扩展,也就是说,这个扩展行为被“延迟”了。但使用百分号闭合的环境变量任会在
读取完毕一条完整语句后立即被扩展。
延迟环境变量扩展特性在CMD中缺省是关闭的,开启它的方法目前有两个:一是CMD /v:on,它会打开一个
新的命令行外壳,在使用exit退出这个外壳之前,延迟扩展特性始终有效,常用于命令行环境中;二是
setlocal EnableDelayedExpansion,它会使环境变量的修改限制到局部空间中,在endlocal之后,延迟扩展特
性和之前对环境变量的修改将一同消失,常用于批处理语句中。
@echo off
::代码2
set "var=test"
for /l %%i in (1 1 1) do (
set "var=cn-dos"
echo.%var%
)
pause
test
请按任意键继续. . .
请你先执行一下代码2
为什么代码2执行后的结果是“test”,而不是“cn-dos” 呢?
分析:
________________________________________________________________________
这是因为cmd读取for这一完整语句后就进行必要的预处理工作,所有能被扩展的变量都已被替换
为之前设定的值了,所以在代码2中执行到“echo.%var%”时实际执行的命令是“echo.test”。
(换句话说,在还没有执行“set "var=cn-dos"”的时候“%var%”就等于“test”了)
________________________________________________________________________
@echo off
::代码3
set "var=test"
for /l %%i in (1 1 1) do (
set "var=cn-dos"
call echo.%%var%%
)
pause
cn-dos
请按任意键继续. . .
请你先执行一下代码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进制的代码
@echo off&setlocal enabledelayedexpansion
:: 代码4
:: Code by CN-DOS terse
set "hx=0123456789ABCDEF"
for /l %%a in (1 1 10000) do (
set /a str=%%a
for /l %%i in (1 1 8) do (
if !str! gtr 0 (
set/a "n=str&15,str>>=4"
for %%i in (!n!) do set h=!hx:~%%i,1!!h!
))
echo %%a 的十六进制为:0x!h!&set "h="
)
pause
@echo off&setlocal enabledelayedexpansion
:: 代码5
:: Code by CN-DOS terse
set "hx=0123456789ABCDEF"
set/p str=:
(for /l %%i in (1 1 8) do (
if !str! GTR 0 (
set/a "n=str&15,str>>=4"
call set h=%%hx:~!n!,1%%!h!
)
)
if not defined h set "h=0"
echo.%str% 的十六进制为:0x!h!)
pause
代码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 ]
Batch Processing Learning Post ① —— Detailed Analysis of Variable Expansion and the "Variable Delay" Principle of the call Command
Preface:
This series of tutorials is suitable for students with a certain batch processing foundation. If you don't understand the content below, it means your foundation is relatively poor. It is recommended that you lurk in the forum for a period of time, read old posts and practice carefully. After coming back, you will definitely understand.
Now let's systematically learn about variable expansion in batch processing and the "variable delay" of the call command.
Note: Unless otherwise specified, the content explained in the batch processing learning post is all in the batch processing environment.
I. Variable Expansion
How does variable expansion work?
@echo off
:: Code 1
set "var=test"
echo.%var%
echo.%%var%
echo.%%var%%
echo.%%%var%%%
echo.%%%var%%%%
pause
test
%var
%var%
%test%
%test%
Press any key to continue...
Please execute Code 1 first.
1. Variable Expansion
(1) When cmd reads a variable statement using "%" for reference, it first checks whether the number of "%" on the left of "var" is odd. If it is odd, it replaces "%var%" with the value of the variable. If it is even, it does not replace it. If the variable is not defined, it is replaced with an empty string.
2. Remove Percent Signs
(1) After "%var%" is replaced with the value of the variable, the percent signs on both sides will naturally be reduced by one.
(2) If the number of percent signs on one side is even, then half of the percent signs are directly removed. If the number of percent signs on one side is odd, then (the number of percent signs + 1) ÷ 2 percent signs are removed. If there are no percent signs, no removal is done.
Let's analyze the last line of code in Code 1 (echo.%%%var%%%%) for students.
(1) Variable Expansion: Because there are three percent signs on the left of "var", and 3 is odd, so "%var%" is replaced with "test". Then "%%%var%%%%" becomes "%%test%%%".
(2) Remove Percent Signs: Because there are two percent signs on the left of "test", so half are removed directly. And there are three percent signs on the right, so (3 ÷ 2 + 0.5) 2 percent signs are removed. So the final result becomes "%test%".
The description in "Replacement Steps of Variable Expansion" may be a bit abstract, but everyone should understand it after practicing and combining with the analysis of "(echo.%%%var%%%%)".
At this point, students should be able to understand the process of environment variable expansion. But one thing must be made clear to students. The above-mentioned "replacement steps" are just to help new students better understand the process of environment variable expansion. In batch processing, the command interpreter does not follow the above rules to expand variables. But students don't need to worry. Although the processing method is different, the result is the same.
Next, we will explain the process of variable expansion from the perspective of the command interpreter interpreting "%" and "variable identifier".
The "%" character is interpreted as a "variable identifier" in batch processing. So in batch processing, "%" belongs to a special symbol. From the perspective of preprocessing, after the command interpreter reads a complete batch processing statement ("%var%"), it first expands the variable. At this time, all "%" in the statement are interpreted as "variable identifiers". After variable expansion is completed, all "%" no longer exist. However, at this time, the command interpreter has not yet parsed the escape character "^". So how to output "%"? We just want to output "%var%" and not let it be interpreted. Then we need to find a way to cancel the special nature of "%", so that the command interpreter does not process it. At this time, the character that is needed to escape "%" is actually "% " itself. So the second identity of the "%" character in batch processing is the "escape character". Note: "%" only escapes "%", which is different from "^".
Let's still analyze "echo.%%%var%%%%" in Code 1.
1. The first "%" after echo. escapes the second "%", at this time the second "%" becomes a normal character, and the command interpreter no longer interprets it. The first "%" is interpreted as an "escape character" by the command interpreter, so it does not exist.
2. The third "%" after echo. and var and the fourth "%" form a complete variable reference, so "var" is replaced with "test". The two "%" used to reference "var" are interpreted as "variable identifiers" by the command interpreter, so they do not exist.
3. Similarly to , the fifth "%" after echo. escapes the sixth "%", at this time the sixth "%" becomes a normal character, and the command interpreter no longer interprets it. At this time, the fifth "%" does not exist.
4. The last, that is, the seventh "%", the command interpreter interprets it as a "variable identifier", so it does not exist.
5. At this time, all processing of "%" is completed. We combine the results of the first four steps, %, test, %, and the final result becomes: %test%.
According to the above analysis process, it can be seen that when two "%" are together, the previous "%" is interpreted as an "escape character" by the command interpreter, and the latter "%" is escaped into a normal character by the previous "%", and follows the principle from left to right.
I don't know if the above explanation can be understood by everyone. Even if it is not understood, it doesn't matter. As long as the content in "Replacement Steps of Variable Expansion" can be understood, because the content in "Replacement Steps of Variable Expansion" is easier to understand. So in the following text and subsequent learning posts, "replacement steps" are still used for explanation.
The steps in "Replacement Steps of Variable Expansion" are laws summarized according to the results of variable expansion, which are easier for new students to understand. But to understand the reason essentially, it is still necessary to understand the above analysis, otherwise you will ask why odd numbers are expanded and even numbers are not expanded, hehe.
Note: Due to the dual characteristics of "%", some "%" naturally do not exist after preprocessing, so some people also call it an "escape character" or "carat".
"Original article, please indicate the source cn-dos&q8249014 when reposting."
II. "Variable Delay" of the call Command
We know that before a command is executed, the command interpreter will perform some necessary interpretation and processing on the command statement. This process is called the "preprocessing work". The "variable expansion" mentioned in the first paragraph is part of the preprocessing work. Let's first look at some knowledge related to preprocessing.
__________________________________________________________________________
Here, I will briefly explain to students what "preprocessing work" is.
In my personal understanding, preprocessing is a process in which the command interpreter interprets and matches commands, which is performed before the command is executed.
So what exactly does "preprocessing work" do?
(1) First, expand the variables referenced using "%".
(2) Match and interpret the characters in the command, such as matching "&" as a command connector.
Rem (3) If there is an if (for) command, check the format of the if (for) command.
Rem (4) If there is an if (for) command, after all variables in the if (for) command statement are expanded, perform conditional processing, and then submit the command statement that meets the conditions to the command main body for execution.
(3) ……Waiting for your exploration.
(4) Perform delayed variable expansion (will process the escape character "^").
(5) After the preprocessing work is completed, submit the command statement to the command main body for execution.
Note: The content commented with Rem above does not require new students to fully understand. Friends with rich batch processing experience should be able to understand.__________________________________________________________________________
In order to help students better understand the following two codes, an article by willsort in this forum is quoted.
Only some supplementary modifications have been made in the text to make the explanation more accurate and convenient for everyone to refer to
Regarding environment variable delay expansion, you can check some instructions using set /?. However, considering its crude translation level, it is recommended to first switch to English display status using chcp 437 before viewing. Since the text has been explained very comprehensively and there are several code examples, it should not be difficult to understand. Only some supplements are made here.
In many visible official documents, a pair of percent signs is used to close the environment variable to complete the replacement of its value. This process is called "expansion", which is actually a first-party concept, referred to from the perspective of the command interpreter. From the perspective of us users, it can be regarded as reference, call or get.
The process of the command interpreter expanding environment variables is roughly as follows: First, read a complete statement of the command line. (Before the command is interpreted and executed, some preprocessing work will be performed.) Then, match the string closed by percent signs. If a matching environment variable is found in the environment space, its value is used to replace the original string and the percent signs themselves. If no match is obtained, an empty string is used to replace it. This process is the "expansion" of the environment variable, which belongs to the preprocessing category of the command line.
A "complete statement" is interpreted by the NT command interpreter CMD as statements containing statement blocks such as "for, if else, ()" and compound statements connected by "&, |, &&, ||" and other connections.
Therefore, when CMD reads a for statement, all statements closed by a pair of parentheses will be read together and necessary preprocessing work will be completed, which includes the expansion of environment variables. Therefore, before all statements in for are executed, all environment variables have been replaced with the values set before for, thus becoming a string constant, and no longer a variable. No matter how those environment variables are modified in for, only the environment variable space is actually affected, not the inside of the for statement.
In order to be able to perceive the dynamic changes of environment variables inside the for statement, CMD designs the feature of delayed environment variable expansion. And in order to distinguish from environment variables closed by percent signs for expansion, after enabling delayed environment variable expansion, to expand the variable delay, English exclamation marks should be used to close the environment variable. That is to say, after CMD reads a complete statement, it will not immediately expand the environment variable closed by English exclamation marks, but will expand it again before executing a certain single statement, that is, this expansion behavior is "delayed". But the environment variable closed by percent signs will still be expanded immediately after reading a complete statement.
The delayed environment variable expansion feature is off by default in CMD. The methods to enable it are currently two: one is CMD /v:on, which will open a new command line shell. Before using exit to exit this shell, the delayed expansion feature is always effective, and it is often used in the command line environment; the other is setlocal EnableDelayedExpansion, which will limit the modification of environment variables to the local space. After endlocal, the delayed expansion feature and the previous modifications to environment variables will disappear together, and it is often used in batch processing statements.
@echo off
:: Code 2
set "var=test"
for /l %%i in (1 1 1) do (
set "var=cn-dos"
echo.%var%
)
pause
test
Press any key to continue...
Please execute Code 2 first.
Why is the result of Code 2 executed "test" instead of "cn-dos"?
Analysis:
________________________________________________________________________
This is because after cmd reads the complete for statement, it performs necessary preprocessing work, and all variables that can be expanded have been replaced with the values set before. So when executing "echo.%var%" in Code 2, the actual command executed is "echo.test".
(In other words, before executing "set "var=cn-dos", "%var%" is equal to "test".)
________________________________________________________________________
@echo off
:: Code 3
set "var=test"
for /l %%i in (1 1 1) do (
set "var=cn-dos"
call echo.%%var%%
)
pause
cn-dos
Press any key to continue...
Please execute Code 3 first.
What is the difference between variable expansion with and without using the call command? (test&cn-dos)
Code 3 only has one more call. Why is the result different from Code 2? Why can Code 3 display "cn-dos"?
How does the call command realize the "variable delay" effect?
Analysis:
_______________________________________________________________________________
Because the call command also defaults to expanding variables when processing the command statement, so after using the call command, there will be one more "replacement step".
(1): When reading a complete statement, the steps of the command interpreter expanding environment variables during preprocessing.
1. Variable Expansion: "call echo.%%var%%", because there are two percent signs on the left of "var", so the variable is not replaced.
2. Remove Percent Signs: Because the percent signs on both sides of "var" are even numbers, so half of the percent signs on both sides are removed and become "%var%".
(2): After the command statement is submitted to the call command, the steps of the call command expanding environment variables internally.
1. Variable Expansion: At this time, "set "var=cn-dos"" has been executed, and the value of var has been defined as "cn-dos", so "%var%" will be expanded to "cn-dos".
2. Remove Percent Signs: There are no percent signs, so no removal is done. So the result is "cn-dos".
Note: The above "replacement steps" are the same as the "(Replacement Steps of Variable Expansion)" in the first paragraph.
_______________________________________________________________________________
The main idea of using call to perform variable delay expansion above is:
(1) Use an even number of percent signs on the left of the variable to reference the variable, so that the variable is not expanded during preprocessing.
(2) After the command statement is submitted to the call command, the call command will expand the variable again when processing the command statement, so as to achieve the purpose of delayed expansion.
Here, new students are requested to compare the results of Code 2 and 3 in combination with the above analysis and understand the reason, and experience the application of the "variable delay" of the call command. This will help the learning of the third paragraph of the example demonstration.
"Original article, please indicate the source cn-dos&q8249014 when reposting."
III. Example Demonstration
Code 4 is a code for converting decimal to hexadecimal written by "terse" in the forum. Code 5 is a code "trimmed" by me.
This code is also the shortest code for converting decimal to hexadecimal that I have seen.
@echo off&setlocal enabledelayedexpansion
:: Code 4
:: Code by CN-DOS terse
set "hx=0123456789ABCDEF"
for /l %%a in (1 1 10000) do (
set /a str=%%a
for /l %%i in (1 1 8) do (
if !str! gtr 0 (
set/a "n=str&15,str>>=4"
for %%i in (!n!) do set h=!hx:~%%i,1!!h!
))
echo %%a 的十六进制为:0x!h!&set "h="
)
pause
@echo off&setlocal enabledelayedexpansion
:: Code 5
:: Code by CN-DOS terse
set "hx=0123456789ABCDEF"
set/p str=:
(for /l %%i in (1 1 8) do (
if !str! GTR 0 (
set/a "n=str&15,str>>=4"
call set h=%%hx:~!n!,1%%!h!
)
)
if not defined h set "h=0"
echo.%str% 的十六进制为:0x!h!)
pause
In Code 4, the variable interception part cannot directly use "set h=!hx:~!n!,1!!h!" or "set h=%hx:~!n!,1%!h!" for interception. So he uses for to pass the variable "!n!" to %%i, and then performs variable replacement "set h=!hx:~%%i,1!!h!".
In the "trimmed" Code 5 of mine, the "variable delay" of the call command is fully utilized, that is: "call set h=%%hx:~!n!,1%%!h!".
Here, only the batch processing skills are discussed, and there is no other meaning. The code of "terse" is still very good, hehe.
Compare Code 4 and 5 above, and experience the application of call "variable delay" again. It is best to fully understand the meaning of each sentence of the code.
Homework: Understand why the value of "str" in "echo.%str% 的十六进制为:0x!h!" in Code 5 is the number you entered instead of 0.
Analyze the execution process of "call set h=%%hx:~!n!,1%%!h!" by yourself.
IV. Summary
Here, some supplements are made for students on the "replacement steps" of variables referenced using "!" after enabling delayed environment variables.
(1) After reading the command statement, cmd will not immediately expand the variable referenced using "!", and the variable referenced using "%" still uses the rules in the first paragraph "(Replacement Steps of Variable Expansion)" for expansion.
(2) Perform preprocessing matching work
(3) Expand the variable referenced using "!" before the command is executed . That is to say, after enabling variable delay, the variable referenced using "!" will be expanded in the last step before executing the sentence after reading the sentence. The expansion rule is: first check whether the variable is defined, if it is, expand it to its value, otherwise replace it with an empty string. In addition, all excess "!" will be replaced with an empty string (interpreted as a "variable identifier"). If it is executed in the cmd command line, the excess "!" will not be replaced.
The difference between variable expansion referenced by "%" and "!":
After reading a single statement or a compound statement, all variables referenced using "%" in the statement will be expanded.
After reading a single statement or a compound statement, all variables referenced using "!" in the statement will not be expanded, but will be expanded in the last step before executing the sentence after reading the sentence.
The above-mentioned "variable expansion" is actually the consciousness of "variable replacement", which may be easier for students to understand.
Well, this lesson ends here.
If there are any improper places in the text, please correct them by forum friends.
"Original article, please indicate the source cn-dos&q8249014 when reposting."
Revised on December 1, 2009
Last edited by q8249014 on 2010-2-4 at 16:52 ]