2012-06-30 228 views
3

我已經看到其他問題,地址部分這個問題,但我沒有看到一個解決方案,完成了整個事情。當然在命令處理器中沒有「while」這樣的東西,並且由於goto:line語句突破了所有循環,因此在繼續下一個值之前,對於特定的持續時間迭代某些值不是一種選擇。WHILE循環在批量循環內FOR循環

這裏是我要去的邏輯流程的僞代碼;命令處理器挫敗了我試圖使其運行到目前爲止。你將如何構造這個(除了批處理腳本和去C#或什麼)?

SET %%durationMinutes=60 
FOR %%X IN (10 20 40 80 160 200 0) DO (
    :: calculate elapsed minutes... 
    WHILE %elapsedMinutes < %%durationMinutes DO (
    :: unrelated hocus pocus here, uses %%X as a variable 
    call :foo %%X 
    // can't use goto to simulate the WHILE loop since it breaks %%X, so...? 
) 
) 

回答

5

這個問題有兩個面。排在首位,這樣一個事實:goto打破任何嵌套IF/FOR命令,但也許更重要的是,雖然組裝goto是非常緩慢的事實。一種解決方案是用無限循環模擬一段時間:for /L %%i in() do ...並在子程序中通過goto分解它。這種解決方案的問題是,for /L不能與goto在同一CMD.EXE背景打破。所以,解決方案是調用一個新的cmd.exe來執行While。

批處理文件在新的cmd.exe執行可能是同一呼叫者的文件,所以我們需要通過在同一個批處理文件的特殊參數控制而執行。此外,我們可以使用輔助變量來使所有這些東西更清晰。那就是:

@echo off 
setlocal EnableDelayedExpansion 

rem While dispatcher 
if "%1" equ "While" goto %2 

rem Definition of auxiliary variables 
set While=for /L %%a in() do if 
set Do=(
set EndW=) else exit 
set RunWhile=cmd /Q /C "%0" While 

echo Example of While 
echo/ 
goto RunMyWhile 

rem Write the While code here 
:MyWhile 
set /A i=0, num=0 
set /P "num=Enter number: " 
%While% !num! gtr 0 %Do% 
    set /A i+=1 
    echo !i!- Number processed: !num! 
    echo/ 
    set num=0 
    set /P "num=Enter number: " 
%EndW% !i! 

rem Execute the While here 
:RunMyWhile 
%RunWhile% MyWhile 
set i=%errorlevel% 
echo/ 
echo While processed %i% elements 

正如你看到的,雖然可以通過ERRORLEVEL返回一個數字結果給調用者的代碼。

你的具體情況:

SET durationMinutes=60 
goto RunMyWhile 

:MyWhile 
:: calculate elapsed minutes... 
%WHILE% !elapsedMinutes! < %durationMinutes% %DO% 
    :: unrelated hocus pocus here, uses %3 as a variable 
    call :foo %3 
    :: calculate elapsed minutes again... 
%EndW% 

:RunMyWhile 
FOR %%X IN (10 20 40 80 160 200 0) DO (
    %RunWhile% MyWhile %%X 
) 

這個主題在this post

+0

+1,一個真正的開放式結尾,而且語法高效,沒有重複的慢GOTO,只有一個慢CMD。 – dbenham

+0

如果batch不在當前目錄中,RunWhile宏應該使用'「%〜f0」'。 – dbenham

1

只要把循環的內容中的子程序。下面是一個簡單的例子僞代碼:

for x in (1 2 3 4 5) { 
    y = 1 
    while (y <= x) { 
    echo y 
    y = y + 1 
    } 
    echo Looping 
} 

而且在批量實現:

for %%x in (1 2 3 4 5) do set x=%%x & call :for_loop 
goto :for_end 
:for_loop 

    set y=1 

    :while_loop 
    if not %y% LEQ %x% goto :while_end 

    echo %y% 
    set /a y=y+1 

    goto :while_loop 
    :while_end 

    echo Looping 

goto :eof 
:for_end 

和輸出:

1 
Looping 
1 
2 
Looping 
1 
2 
3 
Looping 
1 
2 
3 
4 
Looping 
1 
2 
3 
4 
5 
Looping 
3

哈利在his answer使用子程序正確的想法。通常情況下,調用子程序後,外循環FOR變量不可訪問。但是如果子程序有自己的FOR循環,它們「神奇地」再次可用。這可以消除將外部循環值存儲在變量中或將值作爲參數傳遞的需要。

@echo off 
for %%x in (1 2 3 4 5) do (
    echo begin outer loop iteration, x=%%x 
    call :innerLoop 
    echo end of outer loop iteration, x=%%x 
    echo(
) 
echo Outer loop complete 
exit /b 

:innerLoop 
echo inside subroutine, x FOR variable is inaccessible: x=%%x 
for %%y in (1 2 3 4 5) do (
    if %%y gtr %%x goto :break 
    echo within FOR loop inside subroutine: x=%%x y=%%y 
) 
:break 
echo end of subroutine, x FOR variable is inaccessible: x=%%x 
exit /b 

下面是結果:

begin outer loop iteration, x=1 
inside subroutine, x FOR variable is inaccessible: x=%x 
within FOR loop inside subroutine: x=1 y=1 
end of subroutine, x FOR variable is inaccessible: x=%x 
end of outer loop iteration, x=1 

begin outer loop iteration, x=2 
inside subroutine, x FOR variable is inaccessible: x=%x 
within FOR loop inside subroutine: x=2 y=1 
within FOR loop inside subroutine: x=2 y=2 
end of subroutine, x FOR variable is inaccessible: x=%x 
end of outer loop iteration, x=2 

begin outer loop iteration, x=3 
inside subroutine, x FOR variable is inaccessible: x=%x 
within FOR loop inside subroutine: x=3 y=1 
within FOR loop inside subroutine: x=3 y=2 
within FOR loop inside subroutine: x=3 y=3 
end of subroutine, x FOR variable is inaccessible: x=%x 
end of outer loop iteration, x=3 

begin outer loop iteration, x=4 
inside subroutine, x FOR variable is inaccessible: x=%x 
within FOR loop inside subroutine: x=4 y=1 
within FOR loop inside subroutine: x=4 y=2 
within FOR loop inside subroutine: x=4 y=3 
within FOR loop inside subroutine: x=4 y=4 
end of subroutine, x FOR variable is inaccessible: x=%x 
end of outer loop iteration, x=4 

begin outer loop iteration, x=5 
inside subroutine, x FOR variable is inaccessible: x=%x 
within FOR loop inside subroutine: x=5 y=1 
within FOR loop inside subroutine: x=5 y=2 
within FOR loop inside subroutine: x=5 y=3 
within FOR loop inside subroutine: x=5 y=4 
within FOR loop inside subroutine: x=5 y=5 
end of subroutine, x FOR variable is inaccessible: x=%x 
end of outer loop iteration, x=5 

Outer loop complete 
+0

有詳細的解釋,我懷疑這是不確定的行爲,即,它現在可以工作,但可能會停止無預警工作。我不會推薦使用它,特別是因爲唯一的好處是化妝品。(而且,讓我們面對現實吧,如果你擔心化妝品你並沒有使用批次開始!) –

+1

@HarryJohnston - 我知道它可以在XP下工作。我不認爲這是不明確的。 FOR幫助文檔指出,變量是* global *。他們不打擾說明你必須在本地的FOR環境中才能看到它們。但如果我能看到一個,那麼我應該能夠看到所有,否則它不會是全球性的。這不僅僅是化妝品。該功能具有一些有限的好處。它也可能導致問題。在子例程內的FOR循環中使用'%'文字會造成風險。如果隨後的字符被父項用作FOR VAR,'%'字面可能突然變成變量。 – dbenham

+0

事實上,FOR的幫助確實如此。我立場糾正。 –