Page 2 of 3

Re: Is it possible to break loop?

Posted: 26 Jun 2012 00:13
by Aacini
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...

Re: Is it possible to break loop?

Posted: 26 Jun 2012 07:12
by doscode
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.

Re: Is it possible to break loop?

Posted: 26 Jun 2012 07:17
by doscode
Ed Dyreen wrote:
Squashman wrote:

Code: Select all

:main ()
:: (


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

Re: Is it possible to break loop?

Posted: 26 Jun 2012 07:51
by Ed Dyreen
'
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 )

Re: Is it possible to break loop?

Posted: 26 Jun 2012 10:11
by foxidrive
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
)

Re: Is it possible to break loop?

Posted: 26 Jun 2012 10:18
by doscode
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.

Re: Is it possible to break loop?

Posted: 26 Jun 2012 10:18
by Aacini
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

Re: Is it possible to break loop?

Posted: 26 Jun 2012 10:29
by Aacini
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...
)

Re: Is it possible to break loop?

Posted: 26 Jun 2012 11:37
by Aacini
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

Re: Is it possible to break loop?

Posted: 26 Jun 2012 13:31
by doscode
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.

Re: Is it possible to break loop?

Posted: 26 Jun 2012 16:07
by Aacini
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...
)

Re: Is it possible to break loop?

Posted: 27 Jun 2012 00:57
by doscode
@Antonio: I got it. This is the best solution. Thanks. My script works now.

Re: Is it possible to break loop?

Posted: 27 Jun 2012 01:36
by doscode
@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 -->
)

Re: Is it possible to break loop?

Posted: 27 Jun 2012 07:54
by dbenham
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

Re: Is it possible to break loop?

Posted: 08 Jun 2016 18:24
by sambul35
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?