Erroneous GOTO does not break FOR loops

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Erroneous GOTO does not break FOR loops

#1 Post by dbenham » 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.

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
--OUTPUT--

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

jeb
Expert
Posts: 1041
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Erroneous GOTO does not break FOR loops

#2 Post by jeb » 29 Jan 2020 15:32

dbenham wrote:
29 Jan 2020 15:16
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.
But I thought that this is one of the key features :?:
jeb wrote:
10 Jun 2015 15:32
1) A simple EXIT /B or even a goto :existantLabel WILL remove cached code :!:
This works even if multiple (goto) exits multiple call-stack entries, then a single EXIT /B removes all cached blocks,
but only of the just exited entries, all others are still valid.

2) (goto) will not just exits a call-stack entry it will also move the file position at the position after the CALLER command or block
And your own answer in the same thread :D
dbenham wrote:
07 Jun 2015 10:34
:shock: 8) Very cool and elegant
Probably you had thought about this (and you had known it), but when time passes ....

jeb

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Erroneous GOTO does not break FOR loops

#3 Post by dbenham » 29 Jan 2020 20:08

I did say, This may have been "obvious" to others. Yes, I know I have never seen evidence that a cached FOR loop is any different than any other cached code. (well, ignoring the fact that FOR /L is different :wink: ) I just don't recall ever seeing code that explicitly demonstrates (GOTO) treats FOR loops the same as any other cached code - they remain active.

Looking at various Q&A sites, you often see statements that GOTO kills FOR loops. Most people don't say GOTO kills cached code in general.

And often times people don't differentiate between successful and unsuccessful GOTO, even though they have very different results.

I simply decided to explicitly do the experiment to prove what perhaps should be "obvious"

Post Reply