Как я могу "вырваться" из цикла For? - PullRequest
0 голосов
/ 01 мая 2018

Ниже, когда я выполняю команду goto, она просто зависает, и мне нужно Control-C. Я тоже пробовал EXIT /b. Я стараюсь избегать Гото как можно больше. Есть ли способ сделать то, что я хочу?

: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

.

1 Ответ

0 голосов
/ 02 мая 2018

Короткий ответ: нет, вы не можете.


Поскольку вы используете for /L и устанавливаете бесконечный цикл и тот факт, что цикл предварительно обрабатывается и кэшируется перед его выполнением, он не может быть прерван goto; goto нарушает контекст цикла или, более правильно говоря, контекст блока ( / ), поэтому команды в блоке больше не выполняются, но сам цикл все еще выполняется.

Вы можете доказать это с помощью следующего кода:

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

Вы увидите, что echo %%I выполняется только для %%I с 1 до 10, но выполнение не сразу продолжается на echo skipped, но есть заметная задержка, потому что цикл завершает итерацию в в фоновом режиме, хотя команды больше не выполняются.


Есть обходной путь: вы можете создать бесконечный цикл с goto, например так:

: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

Я знаю, что цикл goto медленнее, чем цикл for /L, но это единственный способ создать разрывной бесконечный цикл.

Более быстрый подход заключается во вложении обоих методов цикла: используйте for /L, чтобы выполнить итерацию несколько тысяч раз, и оберните бесконечный цикл goto.


Альтернативный обходной путь - использовать тот факт, что команда exit может прерывать (бесконечные) циклы for /L. Но так как это также выходит из экземпляра cmd, в котором запущен пакетный файл, цикл необходимо поместить в отдельный экземпляр cmd. Конечно, среда полностью отделена от текущей. Решение может выглядеть так:

: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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...