变量延迟,浅见认为就是变量预处理,在事先声明变量,告诉cmd环境哪个先哪个后。默认情况下是停用,可以用两种方法启用/停用:

一、cmd /v:on 和cmd /v:off ,范围在cmd这个环境直至exit 出现退出cmd

二、setlocal enabledelayedexpansion和setlocal disabledelayedexpansion范围在批处理文件范围内,直至endlocal出现中止.

先看看官方帮助set /?后以几个批处理代码注释解释。

=================================================================================

考虑到读取一行文本时所遇到的目前扩充的限制时,延迟环境变量扩充是很有用的,而不是执行的时候。以下例子说明直接变量扩充的问题:

set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "%VAR%" == "after" @echo If you see this, it worked
    )

不会显示消息,因为在读到第一个 IF 语句时,BOTH IF 语句中的 %VAR% 会被代替;原因是: 它包含 IF 的文体,IF 是一个复合语句。所以,复合语句中的 IF 实际上是在比较 "before" 和"after",这两者永远不会相等。同样,以下这个例子也不会达到预期效果:

set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%

原因是,它不会在目前的目录中建立一个文件列表,而只是将LIST 变量设成找到的最后一个文件。这也是因为 %LIST% 在FOR 语句被读取时,只被扩充了一次;而且,那时的 LIST 变量是空的。因此,我们真正执行的 FOR 循环是:

for %i in (*) do set LIST= %i

这个循环继续将 LIST 设成找到的最后一个文件。延迟环境变量扩充允许您使用一个不同的字符(惊叹号)在执行时间扩充环境变量。如果延迟的变量扩充被启用,可以将上面例子写成以下所示,以达到预期效果:

set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "!VAR!" == "after" @echo If you see this, it worked
    )

set LIST=
    for %i in (*) do set LIST=!LIST! %i
    echo %LIST%

如果命令扩展名被启用,有几个动态环境变量可以被扩展,但不会出现在 SET 显示的变量列表中。每次变量数值被扩展时,这些变量数值都会被动态计算。如果用户用这些名称中任何一个定义变量,那个定义会替代下面描述的动态定义:

%CD% - 扩展到当前目录字符串。

%DATE% - 用跟 DATE 命令同样的格式扩展到当前日期。

%TIME% - 用跟 TIME 命令同样的格式扩展到当前时间。

%RANDOM% - 扩展到 0 和 32767 之间的任意十进制数字。

%ERRORLEVEL% - 扩展到当前 ERRORLEVEL 数值。

%CMDEXTVERSION% - 扩展到当前命令处理器扩展名版本号。

%CMDCMDLINE% - 扩展到调用命令处理器的原始命令行。

---------------------------------------------------------------------------------------------------------------------------------

开始批处理文件中环境改动的本地化操作。在执行 SETLOCAL 之后所做的环境改动只限于批处理文件。要还原原先的设置,必须执行 ENDLOCAL。达到批处理文件结尾时,对于该批处理文件的每个尚未执行的 SETLOCAL 命令,都会有一个隐含的 ENDLOCAL 被执行。

SETLOCAL

如果命令扩展名被启用,SETLOCAL 会如下改变:

SETLOCAL 批命令现在可以接受可选参数:
        ENABLEEXTENSIONS / DISABLEEXTENSIONS
            启动或停用命令处理器扩展名。详细信息,请参阅 CMD /?。
        ENABLEDELAYEDEXPANSION / DISABLEDELAYEDEXPANSION
            启动或停用延缓环境变量扩展名。详细信息,请
            参阅 SET /? 。
无论在 SETLOCAL 命令之前它们的设置是什么,这些修改会一直保留到匹配的 ENDLOCAL 命令。如果有一个参数,SETLOCAL 命令将设置 ERRORLEVEL 的值。如果有两个有效参数中的一个,该值则为零。用下列技巧,您可以在批脚本中使用这个来决定扩展名是否可用:

VERIFY OTHER 2>nul
    SETLOCAL ENABLEEXTENSIONS
    IF ERRORLEVEL 1 echo Unable to enable extensions

这个方法之所以有效,是因为在 CMD.EXE 的旧版本上,SETLOCAL不设置 ERRORLEVEL 值。具有不正确参数的 VERIFY 命令将ERRORLEVEL 值初始化成非零值。

=================================================================================

官方解释有些让人犯迷糊,以下几个代码注释部分来解释变量延迟,纰漏之处,请高手斧正.

=================================================================================

@echo off&setlocal enabledelayedexpansion
::第一方演示变量延迟,当输出if you ..延迟启动
::var重复赋值,第一个%var%取的是before
::第二个!var!取的是after,若不开启延迟变量
::不显示因!VAR!取的是before
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "!VAR!" == "after" @echo If you see this, it worked
)
pause>nul

-----------------------------------------------------------------------

@echo off&setlocal enabledelayedexpansion
:: 演示变量延迟,用setlocal disabledelayedexpansion
:: 和setlocal enabledelayedexpansion 相互切换
:: echo %var% 取set var=fds 的值,而echo !var!
:: 取for复合语句中set var=%%i的值;%var%的值与变量延迟
:: setlocal开关无关,但!var!的值与之相关。当变量延迟
:: 处于开状态则取%%i的赋值,反之则取!var!本身.
set var=fds
for /l %%i in (1,1,6) do (
set var=%%i
echo %var%
echo !var!
)
pause>nul&exit

----------------------------------------------------------------

@echo off&setlocal enabledelayedexpansion
::变量里套变量延迟演示
set a=40000
set b=df
set a%b%=70000
set c=!a%b%!
echo %c%
pause>nul

---------------------------------------------------------------

@echo off&setlocal enabledelayedexpansion
::显示2个随机数并截取各数字求和
mode con:cols=40 lines=20 1>nul
color a1
set %random%=%random%
for /f "delims=" %%i in ('set') do set num=%%i&call echo %%num%%&goto be
:be
for /f "tokens=1,2 delims==" %%j in ("%num%") do (
set/a a=%%j
set/a b=%%k
)
for /f %%l in ("%a%%b%") do (
set/a a=%%l
set/a b=%%l
set/a a0=%a:~0,1%
set/a a1=%a:~1,1% 2>nul&set/a a1+=!a0!
set/a a2=%a:~2,1% 2>nul&set/a a2+=!a1!
set/a a3=%a:~3,1% 2>nul&set/a a3+=!a2!
set/a a4=%a:~4,1% 2>nul&set/a a4+=!a3!
set/a b0=%b:~0,1%
set/a b1=%b:~1,1% 2>nul&set/a b1+=!b0!
set/a b2=%b:~2,1% 2>nul&set/a b2+=!b1!
set/a b3=%b:~3,1% 2>nul&set/a b3+=!b2!
set/a b4=%b:~4,1% 2>nul&set/a b4+=!b3!
)
set/a b4+=%a4%
echo 和为:%b4%
pause>nul

出处:http://hi.baidu.com/jadych/item/f6b022a5048b30268819d330

==============================================================================

以下内容为mq0036个人补充:
先来看个变量延迟的例子:

 1 @echo off
 2
 3 setlocal
 4 set aa=aaa:bbb
 5 call :ck %aa%
 6 echo return=%str%
 7 call :ddd
 8 goto :eof
 9
10
11
12 :ck
13 setlocal EnableDelayedExpansion
14 if "a"=="a" (set str2=ErrorOperation)  else (
15 echo else
16 for /f "tokens=1,* delims=:" %%m in ("%~1") do (
17 set str1=%%~m
18 if /I "!str1!"=="aaa" set str2=%%~n
19 )
20 )
21 endlocal & set str=%str2%
22 goto :eof
23
24
25 :ddd
26 echo %zzz%
27 set zzz=old
28 goto :eof

相信各位对上面的程序都能看懂,不过我这里还要写点废话解释解释,高手请跳过。
1.使用setlocal设置变量为局部变量,结束标志是endlocal,如果不是有endlocal则作用范围表示到当前文件结束.
2.变量延迟使用setlocal EnableDelayedExpansion和setlocal DisableDelayedExpansion,如果不使用setlocal DisableDelayedExpansion则作用范围表示到当前文件结束.
      说明:DisableDelayedExpansion只是关闭变量延迟,也就是在这个语句后面的无法使用变量延迟的功能(后面还有讲解)
3.if语句后如果要执行多条语句需要把多条语句使用括号括起来,当使用else时,即使if后只有单条语句,也要括起来。
BAT语法认为括号中的语句就是一条语句。

程序说明:
说变量延迟就要说到局部变量,如果他们嵌套使用,各个变量的取值会怎么样?
第三行,设置局部变量
:ck子程序的功能,是利用延迟把aa变量中根据冒号(:)分割提取字符串,并且带回分割后的字符串
:ddd子程序则是为了验证程序前面的setlocal的嵌套的作用域
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,运行程序,如果修改了程序则关闭当前cmd窗口重新打开cmd。

验证一:
把第三行的setlocal去掉,然后多次运行程序,可以看出第一次执行时,echo %zzz%输出的是ECHO is off.后面再次执行的都输出了old字符串。
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,输入程序文件名运行
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,运行程序,如果修改了程序则关闭当前cmd窗口重新打开cmd。
---------------------------------------------------------------
验证二:
使用endlocal & set str=%str2%是为了把局部变量返回主调函数中
多次调用执行该文件,变量echo %zzz%中的值都是空
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,运行程序,如果修改了程序则关闭当前cmd窗口重新打开cmd。
---------------------------------------------------------------
验证三:
在BAT文件中的一部分是局部变量,一部分是全局变量。修改程序代码如下:
setlocal
echo %aa%
set aa=aaa:bbb
::endlocal
call :ddd
endlocal
goto :eof
:ddd
echo %zzz%
set zzz=old
goto :eof
通过改变endlocal的位置可以看到,在调用语句的后面,但在子程序的前面使用,则会起到局部变量的效果,当放到调用语句的前面则是全局变量的效果。这里测试的是在主程序中调用setlocal的功能,所以endlocal也必须在主程序中使用。
而且setlocal跟子程序有关,如果在子程序中使用setlocal,则在该子程序结束前的endlocal有效,如果不写endlocal则默认作用域到子程序结束,也就是在子程序中使用setlocal则作用域不会超出子程序。看下面的示例:
@echo off
echo %aa%
set aa=aaa:bbb
call :bbb
call :ddd
goto :eof

:bbb
setlocal
echo %zzz%
set zzz=old
::endlocal
echo %xxx%
set xxx=xxx
goto :eof

:ddd
echo %y%
set y=yyyy
运行以上程序,把:bbb子程序中的endlocal启用和禁用,可以查看变量%zzz%和%xxx%的值,
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,运行程序,如果修改了程序则关闭当前cmd窗口重新打开cmd。
---------------------------------------------------------------
验证四:
把if "a"=="a" (set str2=ErrorOperation)...... 这个语句中的括号拿掉,不管条件是否成立,"a"=="a"或"a"=="b",则都会执行else里的语句
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,运行程序,如果修改了程序则关闭当前cmd窗口重新打开cmd。
---------------------------------------------------------------
验证五:
延迟的启用与禁用,修改ck子程序,如下:
:ck
setlocal EnableDelayedExpansion
if "a"=="b" (set str2=ErrorOperation)  else (
echo else
for /f "tokens=1,* delims=:" %%m in ("%~1") do (
set str1=%%~m
if /I "!str1!"=="aaa" set str2=%%~n
)
)
::setlocal DisableDelayedExpansion
for /l %%i in (1,1,3) do (set num=%%i
echo !num!)
setlocal DisableDelayedExpansion
goto :eof
把setlocal DisableDelayedExpansion放到for语句之前和之后的区别,你自己可以测试看看效果,从这里个程序可以看到启用和禁用的区别。
程序运行方式:把程序保存为bat文件,运行cmd并切换到程序所在目录,运行程序,如果修改了程序则关闭当前cmd窗口重新打开cmd。
---------------------------------------------------------------

变量延迟(setlocal)之浅见相关推荐

  1. windows批处理的感叹号和变量延迟扩展

    先来说说变量延迟扩展吧.当然,放狗一搜,就能看到满天飞的关于变量延迟扩展的文章,所以,我这里就简单介绍一下.先来看一段批处理: set str=test if %str%==test ( set st ...

  2. 批处理——感叹号和变量延迟扩展

    先来说说变量延迟扩展吧.当然,放狗一搜,就能看到满天飞的关于变量延迟扩展的文章,所以,我这里就简单介绍一下.先来看一段批处理: set str=test if %str%==test ( set st ...

  3. windows变量延迟_Windows 10的2018年10月更新可能推迟到11月(这就是原因)

    windows变量延迟 Microsoft stopped offering Windows 10's October 2018 Update on October 6, as it was dele ...

  4. SQL Server 2019中SQL表变量延迟编译

    In an article, An overview of the SQL table variable, we explored the usage of SQL table variables i ...

  5. 批处理之坑爹的感叹号和变量延迟扩展

    https://www.cnblogs.com/ini_always/archive/2012/02/16/2355031.html 转载于:https://www.cnblogs.com/vana/ ...

  6. 批处理bat命令--获取当前盘符和当前目录和上级目录

    1. 批处理命令获取当前盘符和当前目录 @echo off rem 设置环境变量延迟 setlocal EnableDelayedExpansion echo 当前正在运行的批处理文件所在路径:!cd ...

  7. windows 批处理 for循环语句

    命令格式:for{%variable |%% variable } in (集合) do command [options] %variable |%% variable: 代表可替换参数.使用%va ...

  8. 学习自旋电子学的笔记06:“扫参数”批量微磁模拟,ubermag介绍,微磁模拟求助

    文章目录 前言 一."扫参数"进行批量微磁模拟 1."扫参数"的基本技巧 2.使用for命令让Boxsi"扫参数"实现批量化运行 二.一个非 ...

  9. APP多平台快速切换

    因为公司的APP需要向多平台发布,并且同一份APP源码会切换厂商发多种版本的APP.然而,虽然我有做厂商的区分文件,但每次源码切换厂商总是耗时,而且手动切换(进行文本覆盖),总有时候会有些漏的和错的. ...

最新文章

  1. 关于 TStringList.Assign - 回复 u9cm 的问题
  2. openresty开发系列17--lua中的正则表达式
  3. 【Vegas原创】终端服务器超出了最大允许连接数 解决方法
  4. Java 8的惰性序列实现
  5. 如何实现软件的远程更新_手机免root终于也能实现远程控制了 这款国产软件真是越来越好用...
  6. python 元组的一点问题
  7. iOS 面试题整理(带答案)二
  8. [数据结构] 伸展树(Splay Tree)原理及若干应用详解(无指针)
  9. Android签名与风险分析
  10. √【物流网络规划】库存和仓储 warehouse
  11. Android 将Assets 目录中的ZIP压缩包解压至本地指定文件中
  12. oracle数据库在linux,怎样在Linux系统中备份Oracle数据库
  13. DNA 5. 基因组变异文件VCF格式详解
  14. 一项采用MasimoO3(R)的前瞻性研究就通气抢救疗法对COVID-19患者脑氧合的效应进行了深入探查
  15. 用Python画个新冠病毒
  16. javafx label设置字体大小_JavaFX-实现文本
  17. toms 尺寸 shoes or boots finds
  18. 在线给程序员出主意:花100万买北京户口,值不值?
  19. 识海日志——时间都去哪了(20140311)
  20. 短视频引流怎么做?如何利用短视频引流?短视频引流技巧

热门文章

  1. c语言中左右对齐的作用,c语言中右对齐的符号
  2. 服务器可以读u盘文件,服务器向u盘拷贝数据库
  3. linux 链接 文件,聊聊 Linux 里的文件链接
  4. java table集合_Java集合类汇总记录--guava篇
  5. JS遮罩插件 -- JqLoad
  6. 工具栏,底部导航栏,可扩展列表视图
  7. ssm三大框架工作原理_蒸发器最常见的三大工作原理
  8. python打包成.exe程序
  9. 《蘑菇街编程题》回文串
  10. 《剑指offer》数组中重复的数字