Короткий ответ: нет, вы не можете.
Поскольку вы используете 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