Is it possible to break loop?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Aacini
Expert
Posts: 1617
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: Is it possible to break loop?

#16 Post by Aacini » 26 Jun 2012 00:13

It is just a clearer way to write an IF with two conditions. If you don't like it, you may write:

Code: Select all

    if !ThisIsLegalNumber! EQU 1 if not defined break (
instead.

Perhaps if you show us your complete code (starting at the outer loop) I can write the exact modification you need...

doscode
Posts: 174
Joined: 15 Feb 2012 14:02

Re: Is it possible to break loop?

#17 Post by doscode » 26 Jun 2012 07:12

dbenham wrote:But you might fret, the context of the outer loop dissapears while I am in the called subroutine, so I can't access the outer loop variable. No worries...

What hasn't been explained is that the variable from the outer loop is available within the inner loop :D 8)

Given that we are in a subroutine, a simpler approach to breaking out of the inner loop is to use EXIT /B instead of GOTO :LABEL.

I tested your code, and the variables from outer context are really accessed in the inner loop in the subroutine. It's great. Thanks. I could use this method, but if I would make working the Antonio's approach, that could be yet more easy.

doscode
Posts: 174
Joined: 15 Feb 2012 14:02

Re: Is it possible to break loop?

#18 Post by doscode » 26 Jun 2012 07:17

Ed Dyreen wrote:
Squashman wrote:

Code: Select all

:main ()
:: (


Why do you write the brackets after soubroutine's label?

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Is it possible to break loop?

#19 Post by Ed Dyreen » 26 Jun 2012 07:51

'
You can write comments after labels, when I lookUp a function I copy/paste the headline, replace the arguments to fit my needs.

Code: Select all

:§processStart_ ( #sArgs,# #fullPathFile, #title,# #args,# #sErr,0 #imin,0, #imax,0, #coopLock,0 #clearEnv,0 )

foxidrive
Expert
Posts: 6033
Joined: 10 Feb 2012 02:20

Re: Is it possible to break loop?

#20 Post by foxidrive » 26 Jun 2012 10:11

Why don't you put a condition in the inner loop and only execute the inner loop if the condition is true.


for /L %%z in (1,1,10) do (

for %%a in (*.*) do (
if "%%~xa"==".txt" (
rem execute inner loop
echo %%a
)
)

echo %%z
)

doscode
Posts: 174
Joined: 15 Feb 2012 14:02

Re: Is it possible to break loop?

#21 Post by doscode » 26 Jun 2012 10:18

foxidrive wrote:Why don't you put a condition in the inner loop and only execute the inner loop if the condition is true.

This is one of the possibilities I could do. But if the Antonio's solution would work, it would be the simplest way. Adding next level of IF condition would make the code a little bit less clear. Now I have two possibilities and will choose the best one.

Aacini
Expert
Posts: 1617
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: Is it possible to break loop?

#22 Post by Aacini » 26 Jun 2012 10:18

doscode wrote:I don't understand your code, why you write it this way.

if !ThisIsLegalNumber! EQU 1 %and% not defined break
What does it mean? I think that it doesn't solve anything. Will this break the loop or not? Next code there.

OK. Let's be more clear about this matter.

If you have a FOR loop nested inside another one this way:

Code: Select all

rem Outer loop:
for %%D in (for-set) do (
   some commands...
   rem Inner loop:
   for %%A in (for-set) do (
      commands of inner loop...
   )
   more commands...
)

You may break the inner FOR this way:

Code: Select all

rem Outer loop:
for %%D in (for-set) do (
   some commands...
   rem Inner loop:
   SET BREAK=
   for %%A in (for-set) do (
      IF NOT DEFINED BREAK (
         commands of inner loop...
         IF SOME_CONDITION SET BREAK=TRUE
      )            <- closing parentheses of new IF
   )               <- original closing parentheses of inner FOR
   more commands...
)

You must pay attention to include ALL original commands of inner FOR inside the new IF.

In the particular case when ALL commands of inner FOR are included in an IF that have not ELSE part this way:

Code: Select all

rem Outer loop:
for %%D in (for-set) do (
   some commands...
   rem Inner loop:
   for %%A in (for-set) do (         <- there are NOT commands
      if condition (                 <- ... between previous FOR and this IF
         commands of inner loop...
      )                              <- there are NOT commands
   )                                 <- ... between closing IF and closing FOR
   more commands...
)

... then you may use the same IF to control the break this way:

Code: Select all

rem Outer loop:
for %%D in (for-set) do (
   some commands...
   rem Inner loop:
   SET BREAK=
   for %%A in (for-set) do (         <- there are NOT commands
      if condition IF NOT DEFINED BREAK (  <- ... between previous FOR and this IF
         commands of inner loop...
         IF SOME_CONDITION SET BREAK=TRUE
      )                              <- there are NOT commands
   )                                 <- ... between closing IF and closing FOR
   more commands...
)

This method is simpler than include an additional IF to control the break like in the first example, but can only be used in this particular case.

In this case, if you want to write ths command:

Code: Select all

if condition if not defined break (
... in a clearer way, you may use the trick to define SET AND=IF and then change it this way:

Code: Select all

if condition %and% not defined break (
... that, in my opinion, is clearer. :wink:

Antonio

Aacini
Expert
Posts: 1617
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: Is it possible to break loop?

#23 Post by Aacini » 26 Jun 2012 10:29

You may also use this approach, that is simpler to write:

Code: Select all

rem Outer loop:
for %%D in (for-set) do (
   some commands...
   rem Inner loop:
   SET BREAK=
   for %%A in (for-set) do IF NOT DEFINED BREAK (
      commands of inner loop...
      IF SOME_CONDITION SET BREAK=TRUE
   )               <- original closing parentheses of inner FOR
   more commands...
)

Aacini
Expert
Posts: 1617
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: Is it possible to break loop?

#24 Post by Aacini » 26 Jun 2012 11:37

dbenham wrote:What hasn't been explained is that the variable from the outer loop is available within the inner loop :D 8)

Dave Benham


This point is "explained" in the FOR help this way:

Code: Select all

    Remember, FOR variables are single-letter, case sensitive, global,
    and you can't have more than 52 total active at any one time.

Didn't you see it? It is the global word! This mean that a FOR variable is the same in any ACTIVE FOR at any nesting level, don't matter if the nested FOR is placed in the same nesting code or in a called subroutine!

The opposing point is that a duplicated FOR variable becomes local from the point it is created on until the FOR ends, hidding any duplicated active global variable:

Code: Select all

@echo off
for %%A in (GlobalA-1 GlobalA-2) do (
   for %%B in (B-1 B-2) do (
      echo/
      echo %%A %%B
      for %%A in (LocalA-1 LocalA-2) do (
         echo %%A %%B
      )
   )
)
Output:

Code: Select all

GlobalA-1 B-1
LocalA-1 B-1
LocalA-2 B-1

GlobalA-1 B-2
LocalA-1 B-2
LocalA-2 B-2

GlobalA-2 B-1
LocalA-1 B-1
LocalA-2 B-1

GlobalA-2 B-2
LocalA-1 B-2
LocalA-2 B-2

This mechanism works at any nesting level.

I think this point is not explained in FOR help; however, we frequently use it when we write FOR commands in subroutines with the same variable of a FOR that may call the subroutine.

Antonio

doscode
Posts: 174
Joined: 15 Feb 2012 14:02

Re: Is it possible to break loop?

#25 Post by doscode » 26 Jun 2012 13:31

Aacini wrote:You may get an equivalent behaviour of breaking the inner loop and passing to the next iteration of the outer loop if you enclose the body of inner loop in an IF controled by a break variable:

Code: Select all

@echo off
for %%D in (1 2 3) do (
   set break=
   for %%A in (1 2 3) do (
      if not defined break (
         echo D=%%D, A=%%A
         if %%A equ 2 set break=TRUE
      )
   )
)


Antonio


And

doscode wrote:I think I have two options. Either to use inner condition (cycles would not be skipped) or to move the inner code to separated subroutine and to call this subroutine from the main loop. Then I can use exit /b

Now when I turn back to your original code, I realized that this is exactly the same as I wanted to do with the condition. But originally I did not understand it at all, and I ask myself what I thought about, that I let myself to be so confused...

I thought that the "break" in your code does some miracle to break the loop, but it does not break the loop at all. It does exactly the same as I planed to do... to add if condition ... which means to add one extra level of brackets. Maybe the subroutine should be more clear because it does not complicate the structure adding one extra level.

Aacini
Expert
Posts: 1617
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: Is it possible to break loop?

#26 Post by Aacini » 26 Jun 2012 16:07

You have not to add one extra level of brackets, just an IF in the same line of the inner FOR:

Aacini wrote:You may also use this approach, that is simpler to write:

Code: Select all

rem Outer loop:
for %%D in (for-set) do (
   some commands...
   rem Inner loop:
   SET BREAK=
   for %%A in (for-set) do IF NOT DEFINED BREAK (
      commands of inner loop...
      IF SOME_CONDITION SET BREAK=TRUE
   )               <- original closing parentheses of inner FOR
   more commands...
)

doscode
Posts: 174
Joined: 15 Feb 2012 14:02

Re: Is it possible to break loop?

#27 Post by doscode » 27 Jun 2012 00:57

@Antonio: I got it. This is the best solution. Thanks. My script works now.

doscode
Posts: 174
Joined: 15 Feb 2012 14:02

Re: Is it possible to break loop?

#28 Post by doscode » 27 Jun 2012 01:36

@Antonio, question:
for ... () do (
if !cnt! EQU 0 SET BREAK=
REM inner loop:
for ... () do (
<-- some code here -->
if !ThisIsLegalNumber! EQU 1 (
SET legalNumber=!second!
SET /A cnt=!cnt!+1
if !cnt! LSS 4 (
SET IP=!IP!!legalNumber!.
) else (
SET IP=!IP!!legalNumber!
echo IP complete:!IP!
SET /A cnt=0
SET /A Search_IP=0
SET /A breaked=1
SET BREAK=TRUE
echo Script goes on ...
)
)
)
) <-------- Endof inner loop
<-- go here - next code here -->
)

I found one more complication. I count 4 numbers. Normally, the script should go to the outer loop in the place of "next code" comment. But when I break the inner loop, the !cnt! is reset so the next outer loop cycle will reset the !BREAK!. So it will continue to add numbers to IP like this: 206.255.3.1867.169.
I need to break the loop when the 4 numbers are completed but I need to jump on the end... It seems to me, that when I set BREAK=true the inner loop is finished immediately? Am I right?

Code: Select all

for ... () do (
if !cnt! EQU 0 SET BREAK=
REM inner loop:
for ... () do (
    <-- some code here -->
    if !ThisIsLegalNumber! EQU 1 (
        SET legalNumber=!second!
        SET /A cnt=!cnt!+1
        if !cnt! LSS 4 (
          SET IP=!IP!!legalNumber!.
          ) else (
          SET IP=!IP!!legalNumber!
          [b]echo IP complete:!IP![/b]
          SET /A cnt=0
          SET /A Search_IP=0
          SET /A breaked=1
          SET BREAK=TRUE
          echo Script goes on ...
          )
      )
    )
)        <-------- Endof inner loop
<-- go here - next code here -->
)
Last edited by doscode on 27 Jun 2012 13:33, edited 1 time in total.

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

Re: Is it possible to break loop?

#29 Post by dbenham » 27 Jun 2012 07:54

Aacini wrote:
dbenham wrote:What hasn't been explained is that the variable from the outer loop is available within the inner loop :D 8)

Dave Benham


This point is "explained" in the FOR help this way:

Code: Select all

    Remember, FOR variables are single-letter, case sensitive, global,
    and you can't have more than 52 total active at any one time.

Didn't you see it? It is the global word! This mean that a FOR variable is the same in any ACTIVE FOR at any nesting level, don't matter if the nested FOR is placed in the same nesting code or in a called subroutine!


Umm - maybe it is obvious to you, but to me, FOR's definition of "global" is not intuitive.

Yes, global implies that you can reference an outer loop variable while in an inner loop.

But my point was that when you CALL a subroutine from within a FOR loop, you lose the context of the FOR loop while in the subroutine and no FOR variables are accessible. But if your subroutine instantiates another FOR loop, then all FOR variables are accessible again while in the subroutine loop. (assuming no variables have bee re-used of course).

I do not think the HELP description adequately describes that behavior. It could be improved by saying that FOR variables are "gobal within a FOR context", rather than simply saying they are "global". And the average person still might not grasp the point without seeing an example.

The "global within a FOR context" design can lead to some nasty surprises. You might write a subroutine with a FOR loop that echos text with a percent literal. The routine works perfectly fine. Then one day you call the routine from within another FOR loop, and all hell breaks loose when the character following the percent literal happens to match a FOR variable in your calling loop. That actually happened to me once in real life.


Dave Benham

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Is it possible to break loop?

#30 Post by sambul35 » 08 Jun 2016 18:24

Aacini wrote:You may get an equivalent behaviour of breaking the inner loop and passing to the next iteration of the outer loop if you enclose the body of inner loop in an IF controled by a break variable:

Code: Select all

@echo off
for %%D in (1 2 3) do (
   set break=
   for %%A in (1 2 3) do (
      if not defined break (
         echo D=%%D, A=%%A
         if %%A equ 2 set break=TRUE)))


Is it possible to add a counter inside such loop, something like this:

Code: Select all

@echo off
set "key=HKCU\certain\Registry\Key"
setlocal EnableDelayedExpansion
for %%D in (1 2 3) do (
   set "count=1" & set break=
   for /l %%A in (0,1,!count!) do (
      if not defined break (
         reg query %key%%%A >nul 2>nul
         if errorlevel 1 (set break=TRUE
         ) else (echo %key%%%A & set /a "count+=1"))))
exit /b


It seems !count! value stays at "1" inside the FOR /L loop no matter where set /a "count+=1" is placed. Any workaround to increment the "end" counter inside 2nd loop values range? Or any alternative approach to place a variable counter value in FOR /L or any type of FOR statement to avoid GOTO loop?

Post Reply