zoukankan      html  css  js  c++  java
  • bat脚本-set(setlocal enabledelayedexpansion) 学习

    设置本地为延迟扩展。其实也就是:延迟变量,全称延迟环境变量扩展。

    事件一:

    @echo off
    set a=4
    set a=5&echo %a%
    pause
    

     解说:为什么是4而不是5呢?在echo之前明明已经把变量a的值改成5了。

    批处理运行命令的机制:批处理读取命令时是按行读取的(另外例如for命令等,其后用一对圆括号闭合的所有语句也当作一行),在处理之前要完成必要的预处理工作,这其中就包括对该行命令中的变量赋值。我们现在分析一下例1,批处理在运行到这句“set a=5&echo %a%”之前,先把这一句整句读取并做了预处理——对变量a赋了值,那么%a%当然就是4了!(没有为什么,批处理就是这样做的。)而为了能够感知环境变量的动态变化,批处理设计了变量延迟。简单来说,在读取了一条完整的语句之后,不立即对该行的变量赋值,而会在某个单条语句执行之前再进行赋值,也就是说“延迟”了对变量的赋值。如何开启变量延迟呢?变量延迟又需要注意什么呢?

    事件二:开启 变量延迟机制!

    @echo off 
    setlocal enabledelayedexpansion 
    set a=4 
    set a=5&echo !a! 
    pause
    

     结果:5
    解说:由于启动了变量延迟,得到了正确答案。变量延迟的启动语句是“setlocal enabledelayedexpansion”,并且变量要用一对叹号“!!”括起来(注意要用英文的叹号),否则就没有变量延迟的效果。分析一下例2,首先“setlocal enabledelayedexpansion”开启变量延迟,然后“set a=4”先给变量a赋值为4,“set a=5&echo !a!”这句是给变量a赋值为5并输出(由于启动了变量延迟,所以批处理能够感知到动态变化,即不是先给该行变量赋值,而是在运行过程中给变量赋值,因此此时a的值就是5了)。

    事件三: (一般通过全局变量保存返回值的比较常见),当前这个示例通过变量传递来保存函数的返回值:

    1 @echo off
    2 ::通过给调用者传递一个变量(var),来保存函数的返回值
    3 call :myFunc var
    4 echo.var:%var%
    5 goto :eof
    6 
    7 :myFunc
    8     set "%1=haha"
    9 goto :eof

    结果:var:haha
    解说:通过给 myFunc 函数传递 var 一个变量,然后 函数中 通过 set "%1=haha" 给第一个参数设置值,也就是给变量设置;

    事件四: 通过 设置局部的可延迟的扩展变量 来实现循环,如下循环5次;

    1 @echo off
    2 ::设置局部的可延迟的扩展变量a
    3 setlocal enabledelayedexpansion
    4 for /l %%i in ( 1,1,5 ) do (
    5     set a=%%i  echo !a!
    6 )
    7 pause

    解释: for /l %%i in(start,step,end) do  ;这个循环的语法;每次将循环变量赋值给a,并打印出来;必须要加 setlocal enabledelayedexpansion 这一句,否则 a变量 预处理时没有这个东西,会不打印或者打印 echo是关闭状态;

    事件五:处理局部变量和全局变量不冲突;SETLOCAL命令能让处理器当做是局部变量,用ENDLOCAL解除局部变量。

     1 @echo off
     2 :: 怎么保证局部变量和全局变量不冲突,SETLOCAL命令能让处理器当做是局部变量,
     3 :: 用ENDLOCAL解除局部变量。
     4 :: ENDLOCAL 会被自动调用,当批处理执行到文件末尾的时候,即GOTO:EOF。
     5 :: SETLOCAL可以很好的保护函数内与外面的变量不会冲突。
     6 
     7 set "var1=i'm goloable var1!"
     8 set "var2=i'm goloable var2!"
     9 
    10 echo.var1 before:"%var1%"
    11 echo.var2 before:"%var2%"
    12 call :myFunc var2
    13 echo.var1 after:"%var1%"
    14 echo.var2 after:"%var2%"
    15 pause && goto :eof
    16 ::传一个参数应用进去
    17 :myFunc
    18 SETLOCAL
    19     set "var1=呵呵呵!"
    20     set "%1=%var1%"
    21     echo.var1 :"local Val1 %var1%"
    22 ENDLOCAL
    23 goto :eof

    执行结果:

    解释: 可以看到 ,代码中 将 var2 引用通过参数传进去,同时在函数中将var1的变量设置为呵呵呵!,但是函数执行完后, var1,和var2都没有变动(尽管var2是以变量的形式传进去的),他们只有在属于的局部区域,赋值才有效,endlocal 执行后,他们又恢复 全局变量的值了;

    事件六:怎么跳过ENDLOCAL的屏障,返回局部变量值?采用”变量扩充“,在SETLOCAL与ENDLOCAL之间的全局变量的值会备份,当退出ENDLOCAL,该值将恢复。让命令处理器来执行ENDLOCAL 和SET命令。

     1 @echo off
     2 :: 返回局部变量
     3 :: 怎么跳过ENDLOCAL的屏障,返回局部变量值?
     4 :: 采用”变量扩充“,在SETLOCAL与ENDLOCAL之间的全局变量的值会备份,当退出ENDLOCAL,该值将恢复。
     5 :: 让命令处理器来执行ENDLOCAL 和SET命令。
     6 
     7 set "aStr=Expect no changed,Even if used in function~"
     8 set "var1=Expect changed"
     9 echo.aStr before:%aStr%
    10 echo.var1 before:"%var1%"
    11 call :myFunc var1
    12 echo.aStr after:%aStr%
    13 echo.var1 after:"%var1%"
    14 pause && goto :eof
    15 
    16 :myFunc
    17 setLocal
    18 set "aStr=Try To Change!"
    19 (ENDLOCAL
    20     set "%1=%aStr%"
    21 )
    22 goto :eof

    执行结果:

    解释:aStr 变量通过全局变量的形式,在 setlocal 和 endlocal 之间赋值,这个赋值肯定是不会影响外部的aStr的值的,怎样将 这个局部设置的值保存下来?如上代码: 在 setlocal 和 endlocal 之外 ,通过 将这个值设置给 传进来的参数变量、或者另一个全局变量,即可将 该局部变量的赋值保存下来并返回;如上图,var1的值变为了 局部赋值:Try To Change!;

    事件七:编写递归函数,Fibonacci函数;让函数局部变量的变换对调用者是可见的,循环调用函数,让变量可重用:

      

     1 @echo off
     2 :: 编写斐波拉里 函数,用来计算多少以内的斐波拉里数! 递归!
     3 set "fst=0"
     4 set "fib=1"
     5 set "limit=10000"
     6 
     7 :: fib 传的是引用, 另两个传的是值; fib最后用来返回值
     8 call :feberlalie fib,%fst%,%limit%
     9 echo. The next Fibonacci number greater or equal %limit% is %fib%. 
    10 pause && goto :eof
    11 
    12 :feberlalie
    13 SETLOCAL
    14 
    15 ::可以利用set /a 进行连续赋值,只要用逗号分开每个变量名就可以了。是下面三行代码的缩写
    16 set /a "Num1=%1,Num2=%2,limit=%3"
    17 :: set /a "Num1=%1"
    18 :: set /a "Num2=%2"
    19 :: set /a "limit=%3"
    20 
    21 :: 在set /a 计算时,可以省略变量的%号或!号,极为方便。 是带百分号的 加法的缩写
    22 :: set /a "Sum=Num1 + Num2"
    23 set /a "Sum=%Num1% + %Num2%"
    24 
    25 echo.Num1 :%Num1%
    26 if /i %Sum% LSS %limit% call:feberlalie Sum,%Num1%,%limit%
    27 (ENDLOCAL
    28     IF "%1" NEQ "" SET "%1=%Sum%"
    29 )
    30 goto :eof

     执行结果:

    总结:定义一个标准的dos batch script function(ps:人家总结的不错,直接拿来用了):

     1      :myFunctionName    -- function description here  函数名
     2     ::           参数描述      -- %~1: argument description here  下面都是函数体
     3     SETLOCAL  
     4     REM.--function body here  
     5     set LocalVar1=...  
     6     set LocalVar2=...  
     7     (ENDLOCAL & REM -- RETURN VALUES  待返回的值
     8         IF "%~1" NEQ "" SET %~1=%LocalVar1%  
     9         IF "%~2" NEQ "" SET %~2=%LocalVar2%  
    10     )  
    11     GOTO:EOF  

    学习参考链接:

    http://blog.csdn.net/xiaoding133/article/details/39252357

    http://www.jb51.net/article/29323.htm

  • 相关阅读:
    2020杭电多校第二场 1006.The Oculus
    2020杭电多校第一场 1005.Fibonacci Sum
    数论——中国剩余定理
    数论——线性同余方程
    数论——乘法逆元
    数论——裴蜀定理
    javascript预解析和作用域
    数组的排序..........加深难度
    值类型和引用类型
    js中的==和===
  • 原文地址:https://www.cnblogs.com/happy-rabbit/p/6283787.html
Copyright © 2011-2022 走看看