0

Expected Input: Start=1, End=500, Interval=100

Expected Output:

1, 100

101, 200

201, 300

301, 400

401, 500

@echo off
set start=1
set end=500   
set interval=100
for /L %%g in (%start%, %interval%, %end%) do (
set first=%%g
set /a last=%first% -1 + %interval%
echo %first% , %last%

)

Actual output:

401 , 401 -1 + 100

401 , 401 -1 + 100

401 , 401 -1 + 100

401 , 401 -1 + 100

401 , 401 -1 + 100

Not sure why first is assigned with 401 value, Appreciate any help

1
  • 1
    Just curious, does this have to be done in batch? There are other languages that may be able to do this easier. Nov 27, 2014 at 1:55

2 Answers 2

5

This is a classic delayed expansion issue. Type help set or set /? from the command prompt for a discussion about delayed expansion (a bit past half way down the full help).

Normal expansion using %var% occurs when the line is parsed. The problem is your entire FOR loop block is parsed in one pass. So you are seeing a constant value that existed before the loop started. The value of 401 is probably left over from a prior run.

The solution is delayed expansion. First you must enable it by using setlocal enableDelayedExpansion. Then you use !var! instead of %var%. This will give the value at execution time instead of at parse time.

Also, there is no need to expand numeric variables when using set /a.

@echo off
setlocal enableDelayedExpansion
set start=1
set end=500
set interval=100
for /L %%g in (%start%, %interval%, %end%) do (
  set /a first=%%g, last=first-1+interval
  echo !first!, !last!
)
5
  • +1 - You beat me. >smile< Nov 27, 2014 at 2:34
  • @EvanAnderson - I'm normally over at StackOverflow. But every now and then a ServerFault question sneaks into my "batch" question filter.
    – dbenham
    Nov 27, 2014 at 2:38
  • I have a real soft spot for batch... I use it for a lot of stuff that I really shouldn't be because it's fun. For perverse values of "fun"... Nov 27, 2014 at 2:40
  • @EvanAnderson - Windows batch happens to be my primary perverse hobby :-) to go along with my more main stream music hobby. You might find the following examples interesting: Throttled parallel processing of a list of tasks using batch, SNAKE.BAT - An arcade style game using pure batch, and Colossal Cave Adventure in batch.
    – dbenham
    Nov 27, 2014 at 3:44
  • I'm definitely going to have to read your scripts in detail. With just a quick perusal I'm already seeing some fun little bits I'll have to co-opt for my own use. (I'm really liking the bit in SNAKE that puts a carriage-return in an environment variable, for example.) Your level of mastery of batch is really impressive, and I'm actually a little embarrassed to have my answer sitting beside yours... >smile< You are driving nails with a screwdriver very precisely and accurately. Nov 27, 2014 at 3:57
3

@dbenham is right on. I'll throw out an alternative. I find the delayed expansion a bit ugly and confusing for longer subroutines, so I'll tend to have a lone call as the "body" of a for loop. Inside the call variable expansion happens "normally". Observe:

@echo off
setlocal
set start=1
set end=500   
set interval=100
for /L %%g in (%start%, %interval%, %end%) do call :_d %%g
endlocal
goto :EOF

:_d
set /a last=%1 - 1 + interval
echo %1, %last%

For this particular case it's more code, to be sure, but for less trivial batch files I think it's a "win".

As an aside: You have no setlocal / endlocal in there, so the values for first and last will persist across executions, assuming you keep running them in the same shell, and give you different results the second time you run your code. I tend to wrap my batch files in a setlocal / endlocal pair to prevent variables I use in the script from "leaking" out into the parent shell's environment.

Finally, I'll echo what @VasiliSyrakis says: If you can avoid using cmd.exe then, by all means, avoid it. I tend to write a lot of stuff in batch but, admittedly, it's a bit like hammering nails with a screwdriver for a lot of problems.

3
  • +1, That is certainly another way to do it. And for many (majority?) of scenarios, it makes sense. However, CALL is extremely SLOW. Not an issue here, but if the loop has many iterations, the impact of using CALL instead of delayed expansion can be painfully obvious.
    – dbenham
    Nov 27, 2014 at 2:45
  • @dbenham - Is there anything "not SLOW" about batch, though? >smile< Nov 27, 2014 at 3:13
  • One nice thing about SETLOCAL is that there is an implicit ENDLOCAL for each active SETLOCAL whenever a script or CALLed routine exits. So the ENDLOCAL is often not needed. There are a few obscure exceptions: for example, a fatal syntax error can break the implicit ENDLOCAL. Of course an explicit ENDLOCAL would do no better in such a case :-)
    – dbenham
    Nov 27, 2014 at 4:10

Not the answer you're looking for? Browse other questions tagged .