設置本地為延遲擴展。其實也就是:延遲變量,全稱延遲環境變量擴展。
事件一:
@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
學習參考鏈接: