在批次環境中執行這一系列簡單的指令:
>set ar[0]=orange
>set ar[1]=apple
>set ar[2]=banana
>for %i in (0,1,2) do echo !ar[%i]!
它輸出以下內容:
>echo !ar[0]!
!ar[0]!
>!ar[1]!
!ar[1]!
>!ar[2]!
!ar[2]!
所以它顯然不會擴展到它的值。我該怎麼做呢?
答案1
資料來源:
第五階段在Windows 命令解釋器 (CMD.EXE) 如何解析腳本?
延遲擴展:僅當延遲擴展打開時,該命令才不在管道兩側的括號塊,並且該命令不是「裸」批次腳本(不含括號、CALL、指令連線或管道的腳本名稱)。
- 命令的每個標記都會被獨立解析以進行延遲擴展。
- 大多數命令解析兩個或多個標記 - 命令標記、參數標記和每個重定向目標標記。
- FOR 指令僅解析 IN 子句標記。
- IF 指令僅解析比較值 - 一個或兩個,取決於比較運算子。
- 對於每個解析的令牌,首先檢查它是否包含任何
!
.如果不是,則不會解析令牌 - 對於^
字元來說很重要。如果令牌確實包含!
,則從左到右掃描每個字元:- 如果它是插入符號 (
^
),則下一個字元沒有特殊意義,插入符號本身將被刪除 - 如果是感嘆號,則搜尋下一個感嘆號(不再觀察到插入符號),擴展到變數的值。
- 連續的開口
!
被折疊成一個!
- 任何剩餘的未配對
!
將被刪除
- 連續的開口
- 在這個階段擴展變數是“安全的”,因為不再檢測到特殊字元(甚至
<CR>
或<LF>
) - 如需更完整的解釋,請閱讀 dbenham 的第二部分 同一線程 - 感嘆號階段
- 如果它是插入符號 (
階段 5.3) 管道加工:僅當命令位於管道的任一側時
管道的每一側都是獨立且非同步處理的。
- 如果命令是cmd.exe的內部命令,或者它是一個批次文件,或者它是一個帶括號的命令塊,那麼它會通過在新的cmd.exe線程中執行
%comspec% /S /D /c" commandBlock"
,因此命令塊會得到階段重新啟動,但這次在命令列模式下。- 如果是帶括號的命令塊,則所有
<LF>
前後帶有命令的命令都將轉換為<space>&
.其他的<LF>
都剝了。
- 如果是帶括號的命令塊,則所有
- 管道指令的處理到此結束。
- 看https://stackoverflow.com/q/8192318/1012053有關管道解析和處理的更多信息
階段 5.5) 執行重新導向:現在將執行第 2 階段中發現的任何重新導向。
- 第 4 階段和第 5 階段的結果可能會影響第 2 階段中發現的重新導向。
- 如果重定向失敗,則命令的其餘部分將中止。請注意,失敗的重定向不會將 ERRORLEVEL 設為 1,除非
||
使用。
- 在你的命令列使用
cmd.exe /v:on /c
set ar[0]=orange
set ar[1]=apple
set ar[2]=banana
for %i in (0,1,2) do cmd.exe /v:on /C"echo !ar[%i]!
- 在你的蝙蝠/指令未聲明的文件
setlocal enabledelayedexpansion
,您還可以使用cmd.exe /v:on /c "command & command | command || command..."
@echo off
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
for %%i in (0,1,2)do cmd /v /c "echo\ !ar[%%i]!"
@echo off
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
setlocal enabledelayedexpansion
for %%i in (0,1,2)do echo\ !ar[%%i]!
enndlocal
@echo off
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana"
for %%i in (0,1,2)do %ComSpec% /v:on /c"echo !ar[%%i]!"
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana"
setlocal enabledelayedexpansion && for %%i in (0,1,2)do echo\ !ar[%%i]!
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off
set "ar[0]=orange" && set "ar[1]=apple" && set "ar[2]=banana"
for %%i in (0,1,2)do <con: %ComSpec% /v:on /c"echo !ar[%%i]!"
call <con: rem./ && %__APPDIR__%timeout.exe /t -1 && endlocal
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
for %i in (0,1,2)do for %i in (0,1,2)do <con: call echo %ar[%i]%
for %i in (0,1,2) do %ComSpec% /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/recho !ar[%i]!
for %i in (0,1,2) do %ComSpec%/v/cecho !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!
for %i in (0,1,2) do cmd/v/recho !ar[%i]!
for %i in (0,1,2) do cmd/v/cecho !ar[%i]!
一些進一步閱讀:
[√]放 /?
[√]命令/?
[√]For循環
[√]For /F 循環
答案2
延遲擴展主要用於將變數值擴展一次以上,尤其是在 For 迴圈中。
引用自https://ss64.com/nt/delayedexpansion.html
延遲擴展將導致批次檔中的變數在執行時而不是在解析時擴展,此選項透過 SETLOCAL EnableDelayedExpansion 命令開啟。
變數擴充意味著用 C:\WINDOWS 的值取代變數(例如 %windir%)
預設情況下,在執行每行之前,擴充只會發生一次。 !每次執行該行時都會執行擴展,或者對於 FOR 循環命令中的每個循環都會執行擴展。首先我們來看這個例子:
set i=0
for /l %%a in (0,1,10) do (
set /a i=%i%+1
echo %i%
)
這裡我們期望輸出數字1到10。
這次我們將嘗試延遲擴充:
setlocal enabledelayedexpansion
set i=0
for /l %%a in (0,1,10) do (
set /a i=!i!+1
echo !i!
)
這次我們將得到預期的輸出,因為每次我們擴展值並且值都會改變。
您的代碼不起作用,因為您必須setlocal enabledelayedexpansion
在代碼開頭添加。
希望有幫助