[Batch] 延遲變數DelayedExpansion

邊做邊學,順便留個筆記,若有錯誤請不吝指教。

Windows batch在變數的處理邏輯上與我們常用的程式語言存在一些落差,
最常見的是在處理迴圈及陣列的時候,
我們先看一個簡單的迴圈程式範例,
以下迴圈範例參考The Blue Nowhere的文章

Example:
set var=0
for %%a in (1 1 1 1 1) do (
    set /a var+=%%a
    echo %var%
)
echo %var%
Output:
0
0
0
0
0
5

按照程式邏輯,我們認為for迴圈裏面echo出來的var值應該遞增,但是實際上卻輸出0。
在迴圈結束後再次輸出var值,卻看到var值有被正確的遞增到5。
這是因為Batch讀入for迴圈時會直接將變數值先全部填入,
所以實際上Batch認知for迴圈裡面的”echo %var%”在讀入時就會被理解成”echo 0″。

為了避免這個問題,我們就需要用到延遲變數展開(EnableDelayedExpansion)。
透過在程式的開頭加入setlocal EnableDelayedExpansion語句,
我們可以使用驚嘆號(!)取代百分比(%)來標示變數,
驚嘆號標示的變數就會被延遲展開:

Example:
setlocal EnableDelayedExpansion
set var=0
for %%a in (1 1 1 1 1) do (
    set /a var+=%%a
    echo !var!
)
echo %var%
Output:
1
2
3
4
5
5

這裡的”echo !var!”就能夠被Batch理解成每次執行到的時候動態抓取變數值了!

另外一個常見的應用場景是陣列:

Example:
set num=1;
set list[%num%]=2;
echo num=%list[%num%]%
Output:
num=num

看起來Batch把”%list[%”和”%]%”理解成變數了,
所以這裡需要另一種符號來與百分號做區隔,
所以我們可以改成這樣:

Example:
setlocal EnableDelayEdexpansion
set num=1;
set list[%num%]=2;
echo num=!list[%num%]!
Output:
num=2

在”echo num=!list[%num%]!”中,
Batch讀入時會先理解成”echo num=!list[1]!”,
再延遲展開list[1]的值,
這樣就可以正確輸出了~