Erroneous GOTO does not break FOR loops
Posted: 29 Jan 2020 15:16
This post is about the erroneous GOTO technique used to exit from a CALL but allow concatenated commands to execute in the context of the CALLer. It was first described in DosTips at Tricky way to detect calls from another batch script. It has been very useful. For example, it enabled creation of an exit function that preserves variables over the endlocal barrier as well as a method to create exception handling in batch files.
One of the key features: previously cached commands within the current block will continue to execute, even after the erroneous GOTO.
But a successful GOTO terminates FOR loops.
This may have been "obvious" to others, but I had never thought to test what happens to FOR loops after an erroneous GOTO.
The following test confirms that the erroneous GOTO does NOT cancel any FOR loop - the loop continues to iterate to completion.
--OUTPUT--
Dave Benham
One of the key features: previously cached commands within the current block will continue to execute, even after the erroneous GOTO.
But a successful GOTO terminates FOR loops.
This may have been "obvious" to others, but I had never thought to test what happens to FOR loops after an erroneous GOTO.
The following test confirms that the erroneous GOTO does NOT cancel any FOR loop - the loop continues to iterate to completion.
Code: Select all
@echo off
setlocal enableDelayedExpansion
set "context=%~nx0"
set context
call :x & echo after call :x !context! context
echo end of %0 Never Reached
exit /b
:x
setlocal
set "context=%0"
set context
call :y & echo after call :y !context! context
echo end of %0 Never Reached
exit /b
:y
setlocal
set "context=%0"
set context
for %%A in (":y Loop A" ":y Loop B") do (
echo %%~A iteration
call :z
echo %%A after call :z !context! context
)
echo end of %0 Never Reached
exit /b
:z
setlocal
set "context=%0"
set context
for %%A in (1 2 3) do (
2>nul (goto)
echo :z Loop %%A !context! context
)
echo end of %0 Never Reached
exit /b
Code: Select all
context=test.bat
context=:x
context=:y
:y Loop A iteration
context=:z
:z Loop 1 :y context
:z Loop 2 :x context
:z Loop 3 test.bat context
":y Loop A" after call :z test.bat context
:y Loop B iteration
context=:z
:z Loop 1 test.bat context
:z Loop 2 !context! context
:z Loop 3 !context! context
":y Loop B" after call :z !context! context
after call :y !context! context
after call :x !context! context
Dave Benham