@echo off setlocal enableextensions setlocal enabledelayedexpansion :: :: Tests for GOTO and CALL. :: :: :: Testing GOTO/CALL from and to within parenthesized blocks. :: echo --------- Testing GOTO within block --------- (echo Block-test 1: Single-line& goto :block2 & echo Unexpected Block-test 1^^!) echo Unexpected echo 1^^! :block2 ( echo Block-test 2: Multi-line goto :block3 echo Unexpected Block-test 2^^! ) echo Unexpected echo 2-3^^! :test_call_block echo Test CALL in block OK from %0 :: We exit this CALL invocation goto :EOF ( :block3 echo --------- Testing CALL within block --------- echo Block-test 3: CALL in block call :test_call_block echo CALL done ) goto :block4 echo Unexpected echo 4^^! ( :block4 echo Block-test 4 OK ) :: :: Testing GOTO/CALL from within FOR and IF. :: This is a situation similar to the parenthesized blocks. :: See bug-report CORE-13713 :: :: Testing CALL within FOR echo --------- Testing CALL within FOR --------- for /L %%A IN (0,1,3) DO ( set Number=%%A if %%A==2 call :out_of_loop_1 %%A if %%A==2 (echo %%A IS equal to 2) else (echo %%A IS NOT equal to 2) ) goto :continue_2 :out_of_loop_1 echo Out of FOR 1 CALL from %0, number is %1 :: We exit this CALL invocation goto :EOF :continue_2 :: Testing GOTO within FOR echo --------- Testing GOTO within FOR --------- for /L %%A IN (0,1,3) DO ( set Number=%%A if %%A==2 goto :out_of_loop_2 echo %%A IS NOT equal to 2 ) echo Unexpected FOR echo 2^^! :out_of_loop_2 echo Out of FOR 2, number is %Number% :: :: Show how each different FOR-loop stops when a GOTO is encountered. :: echo --------- Testing FOR loop stopping with GOTO --------- :: FOR - Stops directly echo --- FOR @echo on for %%A in (1,2,3,4,5,6,7,8,9,10) do ( set Number=%%A if %%A==5 goto :out_of_loop_2a ) echo Unexpected FOR echo 2a^^! :out_of_loop_2a echo Out of FOR 2a, number is %Number% @echo off :: FOR /R - Stops directly echo --- FOR /R :: Use auxiliary directoreis to test for /R mkdir foobar && cd foobar mkdir foo1 mkdir foo2 mkdir bar1 @echo on for /r %%A in (1,2,3,4,5,6,7,8,9,10) do ( set Number=%%~nA if %%~nA==5 goto :out_of_loop_2b ) echo Unexpected FOR echo 2b^^! :out_of_loop_2b echo Out of FOR 2b, number is %Number% @echo off :: Cleanup cd .. & rd /s/q foobar :: FOR /L - Does not stop directly. It continues looping until the end :: but does not execute its body code. This can cause problems e.g. for :: infinite loops "for /l %a in () do ( ... )" that are exited by EXIT /B, :: since the body code stops being executed, but the loop itself continues :: running forever. echo --- FOR /L @echo on for /l %%A in (1,1,10) do ( set Number=%%A if %%A==5 goto :out_of_loop_2c ) echo Unexpected FOR echo 2c^^! :out_of_loop_2c echo Out of FOR 2c, number is %Number% @echo off :: FOR /F - Stops directly. echo --- FOR /F @echo on for %%T in ( "1:2:3" "4:5:6:7" "8:9:10" ) do ( set "pc=%%~T" for /f "delims=" %%A in (^"!pc::^=^ % New line % !^") do ( set Number=%%A if %%A==5 goto :out_of_loop_2d ) ) echo Unexpected FOR echo 2d^^! :out_of_loop_2d echo Out of FOR 2d, number is %Number% @echo off :: Testing CALL within IF echo --------- Testing CALL within IF --------- if 1==1 ( call :out_of_if_1 123 echo Success IF echo 1 ) goto :continue_3 :out_of_if_1 echo Out of IF CALL from %0, number is %1 :: We exit this CALL invocation goto :EOF :continue_3 :: Testing GOTO within IF echo --------- Testing GOTO within IF --------- if 1==1 ( goto :out_of_if_2 echo Unexpected IF echo 2a^^! ) echo Unexpected IF echo 2b^^! :out_of_if_2 echo Out of IF ok :: Same, but with line-continuation at the closing parenthesis of the IF block. if 1==1 ( :labelA echo A ) ^ else ( :labelB echo B goto :continue ) :: We are jumping inside the IF, whose block will be interpreted as :: separate commands; thus we will also run the :labelB block as well. goto :labelA :: :: Next suite of tests. :: :continue :: Testing EXIT within IF echo --------- Testing EXIT within IF --------- :: Use a CALL context, and we will only check EXIT /B. call :doExitIfTest 1 call :doExitIfTest 2 goto :finished :doExitIfTest if %1==1 ( echo First block exit /b echo Unexpected first block^^! ) else ( echo Second block exit /b echo Unexpected second block^^! ) echo You won't see this^^! exit /b :: :: Finished! :: :finished echo --------- Finished -------------- goto :EOF :: Subroutine to set errorlevel and return :: in windows nt 4.0, this always sets errorlevel 1, since /b isn't supported :setError exit /B %1 :: This line runs under cmd in windows NT 4, but not in more modern versions.