windows - Hvordan kan jeg 'break' ud af en For-loop?

Indlæg af Hanne Mølgaard Plasc

Problem



Nedenfor, når jeg udfører kommandoen goto, hænger det bare, og jeg skal Control-C. Jeg forsøgte også EXIT /b. Jeg forsøger at undgå at gå så meget som muligt. Er der en måde at gøre, hvad jeg vil have?


:SUB\_bigRandLooper

set /a lcv=0

FOR /L \%\%s IN ( 0 , 0 , 1 ) DO (

    set big-rand=!random:~-4!
    echo big-rand is !big-rand!
    set /a lcv=\%lcv+1
    if !big-rand! GTR 9900 goto bigRandLooperWrapup
)

:bigRandLooperWrapup

echo biggest-rand is \%big-rand\%
echo lcv is \%lcv\%

EXIT /B


.

Bedste reference




Det korte svar er: Nej, det kan du ikke.





Da du bruger for /L og etablerer et uendeligt sløjfe, og det faktum, at sløjfen er forbehandlet og cachelagret, før den udføres, kan den ikke afbrydes af goto; goto bryder loopkonteksten eller mere korrekt talet (/) blokkonteksten, så der ikke udføres flere kommandoer i blokken, men selve loopen kører stadig.


Du kan bevise dette ved hjælp af følgende kode:


for /L \%\%I in (1,1,100000) do (
    echo \%\%I
    if \%\%I equ 10 goto :SKIP
)
:SKIP
echo skipped


Du vil se, at echo \%\%I kun udføres for \%\%I fra 1 til 10, men udførelsen fortsætter ikke straks ved echo skipped, men der er en bemærkelsesværdig forsinkelse, fordi sløjfen afslutter iterating i baggrunden, selvom der ikke udføres flere kommandoer.





Der er dog et arbejde rundt: Du kunne etablere en uendelig sløjfe med goto som sådan:


:SUB\_bigRandLooper

set /A lcv=0
:bigRangLooperLoop
set big-rand=!random:~-4!
echo big-rand is !big-rand!
set /A lcv+=1
if !big-rand! gtr 9900 goto :bigRandLooperWrapup
goto :bigRangLooperLoop

:bigRandLooperWrapup
echo biggest-rand is \%big-rand\%
echo lcv is \%lcv\%
exit /B


Jeg ved, at goto -sløjfen er langsommere end for /L -sløjfen, men det er den eneste måde at skabe en ubrudt uendelig sløjfe på.


En hurtigere tilgang er at nest begge loop metoder: brug for /L til at gentage et par tusinde gange og pakke en uendelig goto loop rundt.





Et alternativt arbejde er at gøre brug af det faktum, at kommandoen exit kan bryde (uendelige) for /L sløjfer. Men da dette også går ud af cmd eksemplet, kører batchfilen i, skal sløjfen placeres i et separat cmd eksempel. Naturligvis er miljøet helt adskilt fra den nuværende. En løsning kan se sådan ud:


:SUB\_bigRandLooper
@echo off
rem // Check for argument, interpret it as jump label if given:
if not "\%~1"=="" goto \%~1

rem /* Establish explicit `cmd` instance for executing the `for /L` loop;
rem    the `for /F` loop implicitly creates the new `cmd` instance for the command
rem    it executes, so we do not have to explicitly call `cmd /C` here; the resulting
rem    values are echoed by the sub-routine and captured here by `for /F`: */
for /F "tokens=1,2" \%\%I in ('"\%~f0" :bigRandLooperLoop') do (
    rem // Assign captured values to environment variables:
    set "big-rand=\%\%I" & set "lcv=\%\%J"
)

:bigRandLooperWrapup
echo biggest-rand is \%big-rand\%
echo lcv is \%lcv\%
exit /B

:bigRandLooperLoop
setlocal EnableDelayedExpansion
set /A lcv=0
for /L \%\%s in (0,0,1) do (
    set big-rand=!random:~-4!
    rem /* Explicitly redirect this output to the console window to prevent it from
    rem    being captured by `for /F` in the main routine too: */
    > con echo big-rand is !big-rand!
    set /A lcv+=1
    if !big-rand! gtr 9900 (
        rem // Output found values in order to be able to capture them by `for /F`:
        echo !big-rand! !lcv!
        rem // Break loop and leave current `cmd` instance:
        exit
    )
)
endlocal