- 要回答这个问题,先要解释一点batch脚本的执行过程
Batch脚本的执行,按行为单位,读入一行,分析一行(parse),执行一行(execute)。
- 一行指的是一条完整语句,所以一个语句块(所有括号括起来的多条语句)也是作为一行处理的。
if condition (
statement1
statemetn2
statement3
)
上述这个if语句就是作为一行来处理的,一次性分析(parse)。
- 分析过程要做很多事,包括变量替换,把%VAR%替换成值,以及把双%%替换成单%。
- 然后执行。
- 有了这个背景,下面我们抛出需求解决的问题
@echo off
setlocal
set INPUT=aaa.bat
IF u==u (
set OUTPUT=%INPUT%
echo INPUT=%INPUT%, OUTPUT=%OUTPUT%
)
endlocal
运行一下:
INPUT=aaa.bat, OUTPUT=
问题是OUTPUT没有值,是不是很奇怪。这其实就是脚本分析的流程;
前面我们提到语句块"()"是作为一行来一起分析的,所以这里:
IF u==u (
set OUTPUT=%INPUT%
echo INPUT=%INPUT%, OUTPUT=%OUTPUT%
)
其分析阶段结束后,这等于是
IF u==u (
set OUTPUT=aaa.bat
echo INPUT=aaa.bat, OUTPUT=
)
因为是一次性分析的,所以前面的set OUTPUT=
语句的结果并没有作用到后一条输出语句,前面set语句是执行后OUTPUT才有希望的值,这就是分行和执行的差异。
解决办法是使用延迟扩展(EnableDelayedExpansion),让后一条的echo语句延迟扩展,指定前面的set语句执行完成;语法是:
- 定义setlocal EnableDelayedExpansion
- 使用
!var!
代替%var%
,表示这个变量要延迟扩展。
@echo off
setlocal
set INPUT=aaa.bat
setlocal EnableDelayedExpansion
IF u==u (
set OUTPUT=%INPUT%
echo INPUT=%INPUT%, OUTPUT=!OUTPUT!
)
endlocal
endlocal
几点注意:
- 替换
%OUTPUT%
为!OUTPUT!
,表示OUTPUT变量需要延长扩展。 - 格式
%VAR%
还是保留在分析(parse)阶段替换,只是!VAR!
延迟到执行阶段才替换。 - 至于INPUT变量,也可以替换成!INPUT!,这个例子没有替换,是因为INPUT的值没有发生变化,在整个if块分析阶段值已经确定,且不再变化。
网友评论