2012-06-30 177 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的帮助确实如此。我立场纠正。 –