批处理中延迟变量扩展与预处理

批处理中延迟变量扩展与预处理

看这样一个批处理,迭代显示1到20:

示例1

@echo off
for /l %%i in (1 1 20) do echo %%i
pause
这个很简单,那么如果我们不用 %%i来显示,而启用一个新的变量名 hanye呢?
示例2错误

@echo off
for /l %%i in (1 1 20) do (
set hanye=%%i
echo %hanye%
)
pause
      运行结果并没有显示1到20,而是显示:ECHO处于关闭状态。我们知道,出现这个显示,是因为 echo 后面什么也没有,如果跟了变量,则变量为空。那么,为什么变量为空了呢? set hanye=%%i不是为变量赋值了吗?通过示例1,我们也知道 %%i 确实获得了数值。
  在这里,我们要引入一个重要的概念——预处理机制:批处理读取命令时是按行读取的(另外例如 for 命令等,其后用一对圆括号闭合的所有语句也当作一行),在处理之前要完成必要的预处理工作,这其中就包括对该行命令中的变量赋值。在不启用变量延迟,也不对变量动态捕获其扩展变化时,变量在预处理阶段不作改变。
  现在,我们看示例2:在 set hanye=%%i echo %hanye% 之前,不存在变量 hanye ,即为空。而 set hanye=%%i是在更改变量 hanye的数值,这个更改在这一整句完成前不会生效。但echo %hanye% 却又处在生效完成前,即包括在预处理这一句的内部,所以无法显示新获取的值,就显示原来的值——空。
  如果将 echo %hanye% 放在预处理之后,即 ) 的下面,我们就会看到 %hanye%的数值,当然,这个时候只显示5。

  回过头来,我们看示例1和示例2,变量 %%i 的数值由 for 直接赋值,在预处理时,%%i 的值并没有变化。
  我们将示例2改成这样,就可以正常显示了,见示例3:

示例3

@echo off&setlocal enabledelayedexpansion
for /l %%i in (1 1 20) do (
set hanye=%%i
echo !hanye!
)
pause

Setlocal

  开始批处理文件中环境变量的本地化。本地化将持续到出现匹配的 endlocal 命令或者到达批处理文件结尾为止。

语法

setlocal {enableextension | disableextensions} {enabledelayedexpansion | disabledelayedexpansion}

参数

enableextension
    启用命令扩展,直到出现匹配的 endlocal 命令,无论 setlocal 命令之前的设置如何。
disableextensions
    禁用命令扩展,直到出现匹配的 endlocal 命令,无论 setlocal 命令之前的设置如何。
enabledelayedexpansion
    启用延迟的环境变量扩展,直到出现匹配的 endlocal 命令,无论 setlocal 命令之前的设置如何。
disabledelayedexpansion
    禁用延迟的环境变量扩展,直到出现匹配的 endlocal 命令,无论 setlocal 命令之前的设置如何。
/?
    在命令提示符显示帮助。

注释


1、使用 setlocal
    当您在脚本或批处理文件外使用 setlocal 时,将没有效果。
2、更改环境变量
    运行批处理文件时使用 setlocal 更改环境变量。运行 setlocal 后对环境所作的更改在批处理文件本地。Cmd.exe 在遇到 endlocal 命令或者到达批处理文件的结尾时将恢复上一次的设置。
3、在批处理程序中可以包含多个 setlocal 或 endlocal 命令(嵌套)。
4、测试批处理文件中的命令扩展

    setlocal 命令设置 ERRORLEVEL 变量。如果遇到 {enableextension | disableextensions} 或 {enabledelayedexpansion | disabledelayedexpansion},ERRORLEVEL 变量将设置成 0 (0)。否则,该变量将被设置成 1 (1)。在批处理脚本中使用该命令可以确定扩展是否可用,例如:
verify other 2>nul setlocal enableextensions if errorlevel 1 echo Unable to enable extensions
因为当禁用命令扩展时 cmd 不会设置 ERRORLEVEL 变量,所以当通过无效参数使用 setlocal 命令时 verify 命令将 ERRORLEVEL 变量初始化为非零值。另外,如果通过 {enableextension | disableextensions} 或 {enabledelayedexpansion | disabledelayedexpansion} 参数使用 setlocal 命令,而且没有将 ERRORLEVEL 变量设置成 1 (1) 时,则命令扩展将不可用。


启用延迟的环境变量扩展

    setlocal enabledelayedexpansion ,就是启用变量延迟,我们可以形象的认为是启用了“对变量动态捕获扩展变化”。而 ! 括起来的变量,就是要动态捕获扩展的目标变量,如果不需要,可以继续使用 % 括变量。
  那么,什么情况下需要启用变量的延迟呢?在复合语句中,一旦变量需要发生扩展变化,就需要启用。
  我们看一下示例4

@echo off&setlocal enabledelayedexpansion
set han=1
set han=2 &echo !han!
pause
在预处理这一复合句时, set han=2 将在完成这一句时才生效。在没有完成这一句时,变量 han 的数值依然是1。现在,我们来看一个复杂点的复合句:
示例5 显示数列01-20,并使用if判断
@echo off
for /l %%i in (1 1 20) do if %%i lss 10 (echo 0%%i) else echo %%i
pause
  当 for 在第一次循环时,为 %%i 赋值为1,其后的 if %%i 时,使用的依然是这个数值;在 echo 0%%i 时也依然用1这个数值;在 echo %%i 时,还是用1这个数值。在整个预处理这一整句的过程中, %%i 并没有发生变化,所以不需要变量延迟以动态扩展。现在,我们来他另一个批处理示例:
示例6 显示数列01-20,并使用set补0
@echo off&setlocal enabledelayedexpansion
for /l %%i in (1 1 20) do (
set han=0%%i
echo !han:~-2!
)
pause
  在这一示例中,%%i 依然不需要动态变量扩展,因为他在预处理时不发生变化,但变量 han 则不同,他从空变成了有数值,发生了变化,所以需要变量延迟并动态扩展他。

关于 %%i

需要说明一个问题,%%i 是可以被作为普通变量名使用的,上面的示例6就可以写成如下示例7
@echo off&setlocal enabledelayedexpansion
for /l %%i in (1 1 20) do (
set %%i=0%%i
echo !%%i:~-2!
)
pause
  但是,%%i 做为变量使用,并作为截取、替换、运算等时的变量名,仅限于为其赋值的 for 的 do ()的内部。
  那么, set %%i=0%%i 和 echo !%%i:~-2! 可以用 & 连接起来吗?可以的,但问题也出来了,如下示例8(错误


@echo off&setlocal enabledelayedexpansion
for /l %%i in (1 1 20) do set %%i=0%%i & echo !%%i:~-2!
pause
  运行后,仅显示一列的一位数字,那么那另一列的一位数哪去了呢?我们把 echo !%%i:~-2! 改成 echo !%%i:~-3! 就可以看到了。问题出在哪了呢?原来,当 set 与其他命令用 & 连接起来的时候,中间是不能有空格的,否则 set 会把空格当做给变量所赋的值的一部分。所以,示例8的正确写法如下:
示例9:
@echo off&setlocal enabledelayedexpansion
for /l %%i in (1 1 20) do set %%i=0%%i&echo !%%i:~-2!
pause
  凡事皆有例外, set 和 %%i 也是如此。也就是说,不能有这样的表但式: set /a %%i=%%i+10 , %%i 不能在 set /a 中做设置的变量名,否则提示错误“运算符不存在。”。必须写成: set /a hanye=%%i+10 。如下示例:迭代-3到1(步长为1),并将每个结果再加10,然后为1-9前补0。
示例10
@echo off&setlocal enabledelayedexpansion
for /l %%i in (-3 1 1) do (
set /a hanye=%%i+10
set %%i=0!hanye!
echo !%%i:~-2!
)
pause

关于批处理参数

先不转了,太多了。。。
转自:
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值