2

I have an old MS DOS computer running DOS 7.10 (ver command gives: windows 98 ver 4.10.2222). I have to make a batch script that basically runs a command 10 or whatever times. I tried using the for command but it gave me ILLEGAL Command For So now I have:

@ECHO off
SET COUNT=0

:MyLoop
IF "%COUNT%" == "10" GOTO EndLoop
ECHO %COUNT%
SET /a COUNT+=1
:EndLoop 
ECHO done

However, this gives me an infinite loop of 0 as if set command is not working. The command DOES work in CMD in windows 10 though. Can anyone suggest what I am doing wrong? Or a way to implement a for loop in DOS 7 batch file.

WaleeK
  • 71
  • 8
  • You need to look into [delayed expansion](https://ss64.com/nt/delayedexpansion.html). – Jeff Zeitlin Mar 27 '18 at 13:24
  • 3
    @JeffZeitlin - DOS doesn't have delayed expansion. – SomethingDark Mar 27 '18 at 13:26
  • «blink» OK, I somehow read that as referring to the command prompt under _Windows_ 7. – Jeff Zeitlin Mar 27 '18 at 13:30
  • 1
    I don't have a Windows 98 machine to test, but I'm fairly certain that it's the line `set /a count+=1` that's the problem. Try expanding it to `set /a count=%count%+1` – SomethingDark Mar 27 '18 at 13:31
  • 3
    Rereading the question, I'm not even sure that Win98 command line supported SET /A; variables prior to Windows XP - maybe even _in_ XP - were always strings, not numeric. I recall back in those days that in order to loop five times, I ended up having to do `FOR %I IN (1 2 3 4 5) ...` – Jeff Zeitlin Mar 27 '18 at 13:33
  • 1
    Yes, @JeffZeitlin, in DOS, there is no `set /A`; neither is `for /L`. So you have to use either `for %%I in (1 2 3 ...) do`, or, if you want to use a `goto` loop, `set "COUNT=%COUNT%_"` and `if "%COUNT%"=="___..."`. – aschipfl Mar 27 '18 at 13:45
  • but then the thing remains that I have to type it a 1000 times in both cases if I have a large loop... – WaleeK Mar 27 '18 at 13:54
  • N. B.: In your non-working code you are missing `goto MyLoop` immediately before `:EndLoop`! – aschipfl Mar 27 '18 at 13:55
  • why do you need to support DOS or Windows 98? even in Windows 98 [using VBS, WSF or JScript would be much better](https://en.wikipedia.org/wiki/Windows_Script_Host) – phuclv Mar 27 '18 at 15:38
  • 3
    It is quite easy to test a batch file on newer Windows using `cmd.exe` as command interpreter on compatibility with `command.com`. Start the batch file on newer Windows with `setlocal DisableExtensions` and `cmd.exe` interprets the batch file like `command.com`. `cmd /?` outputs (most) commands affected by enabled/disabled command extensions. The individual help of each affected command explains which features/options require enabled command extensions. Once a batch file is running on newer Windows with disabled command extensions, it's time for testing it on MS-DOS or Windows 95/98. – Mofi Mar 27 '18 at 16:53

4 Answers4

3
for %%a in (1 2 3 4 5 6 7 8 9 10) do echo %%a

should count 1 to 10 for you.

Beyond that, you'd need to be more explicit in your requirements.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Damn was hoping for a more elegant solution to be honest, since if i have to iterate a 1000 times, I will have to count to a 1000... – WaleeK Mar 27 '18 at 13:53
  • That can be done. We need to know what you are trying to do so we're not producing all of the possible solutions for what you *might* be doing. – Magoo Mar 27 '18 at 14:00
  • Ah ok, so I am trying to create a batch file which I will use to call upon two separate programs one at a time. I have this spectrometer, whose aperture will be controlled by a program and a step motor with a light source, so basically I want to open the aperture in steps through program 1 and take the reading, then the motor will be moved via program 2 to end the loop and rinse and repeat. So in theory: have a loop for i = 1 to 1000 or w.e. (have to decide after seeing a couple of results) call program 1 <- will do its thing call program 2 <- will do its thing end loop – WaleeK Mar 28 '18 at 12:23
3

In MS-DOS, there is no arithmetics option /A for the set command. There is also no /L option for for loop.

So you either have to do it like this:

@echo off
set COUNT=

:LOOP
if "%COUNT%"=="__________" goto QUIT
set COUNT=%COUNT%_
echo %COUNT%
goto LOOP
:QUIT
echo Done

Or like this:

@echo off
for %%I in (1 2 3 4 5 6 7 8 9 10) do echo %%I
echo Done

If you want to do many iterations, you could help yourself like this for the first approach:

@echo off
rem // This performs 1000 iterations:
set COUNT=
set LIMIT=__________
set LIMIT=%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%
set LIMIT=%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%%LIMIT%

:LOOP
if "%COUNT%"=="%LIMIT%" goto QUIT
set COUNT=%COUNT%_
echo %COUNT%
goto LOOP
:QUIT
echo Done

Or like this for the second one:

@echo off
rem // This performs 1000 iterations:
for %%I in (1 2 3 4 5 6 7 8 9 10) do for %%J in (1 2 3 4 5 6 7 8 9 10) do for %%K in (1 2 3 4 5 6 7 8 9 10) do echo %%I, %%J, %%K
echo Done
aschipfl
  • 33,626
  • 12
  • 54
  • 99
3

This Batch file do what you requested. As is, this example count up to 123, but it can count up to 999 (1000 times, as you requested). If you need more digits, just add the corresponding sections...

EDIT 03/27/2018: Code modified as suggested in comment

EDIT 03/29/2018: Second attempt

@echo off
if not "%1" == "" goto %1

set myself=%0

set count1=0

:MyLoop
   if "%count3%%count2%%count1%" == "123" goto EndLoop
   echo %count3%%count2%%count1%
   call %myself% :incCount
goto MyLoop
:endLoop
echo Done
goto :EOF


:incCount
call %myself% :incDigit %count1%
set count1=%digit%
if %carry% == 0 goto endIncCount
call %myself% :incDigit %count2%
set count2=%digit%
if %carry% == 0 goto endIncCount
call %myself% :incDigit %count3%
set count3=%digit%
:endIncCount
goto :EOF

:incDigit digit
set carry=0
if not "%2" == "" goto next1
   set digit=1
   goto endIncDigit
:next1
if not %2 == 9 goto next2
   set digit=0
   set carry=1
   goto endIncDigit
:next2
if %2 == 8 set digit=9
if %2 == 7 set digit=8
if %2 == 6 set digit=7
if %2 == 5 set digit=6
if %2 == 4 set digit=5
if %2 == 3 set digit=4
if %2 == 2 set digit=3
if %2 == 1 set digit=2
if %2 == 0 set digit=1
:endIncDigit

:EOF

EDIT: New method added

This simpler approach can manage any number of digits in the counter with no modifications:

@echo off
if not "%1" == "" goto %1

set myself=%0

set count=0

:MyLoop
   call %myself% :incCount 
   echo %printCnt%
if not "%printCnt%" == "123" goto MyLoop
echo Done
goto :EOF


:incCount
set newCnt=
set printCnt=
set carry=1
for %%a in (%count%) do call %myself% :incDigit %%a
set count=%newCnt%
if %carry% == 0 goto :EOF
set count=%count%,1
set printCnt=1%printCnt%
goto :EOF

:incDigit digit
set digit=%2
if %carry% == 0 goto endIncDigit
if not %2 == 9 goto next
   set digit=0
   goto endIncDigit
:next
if %2 == 8 set digit=9
if %2 == 7 set digit=8
if %2 == 6 set digit=7
if %2 == 5 set digit=6
if %2 == 4 set digit=5
if %2 == 3 set digit=4
if %2 == 2 set digit=3
if %2 == 1 set digit=2
if %2 == 0 set digit=1
set carry=0
:endIncDigit
set newCnt=%newCnt%,%digit%
set printCnt=%digit%%printCnt%

:EOF
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • 1
    Good try, but command.com can't call labels. Also the extended set syntax was unknown. The basic of your idea should work nevertheless – jeb Mar 28 '18 at 00:41
  • a little help if you don't mind, sorry I am a bit uncertain... if i try to implement your script as is, it gives me syntax error and an infinite loop with output as: 0 syntaxerror – WaleeK Mar 28 '18 at 13:10
  • Ops! My fault... **`:(`** Change `if "%1" neq "" goto %1` by `if not "%1" == "" goto %1` (I already did it in the code). If still show an error, remove the `@echo off` line, change the `"123"` by `"2"`, run the program again and report the exact line where the error occurs... – Aacini Mar 28 '18 at 15:04
  • Ok yes that helped, now the loop can go up till 9 after which it starts giving syntax error. – WaleeK Mar 29 '18 at 10:52
  • I tried removing the & and making it a separate if condition in sequence, that made the code go from 1 to 9 but then the pc runs out of memory space for the variable after a couple of loops if that helps – WaleeK Mar 29 '18 at 12:55
  • Ok. I modified the code again. This debug process would be much simpler if you post the _exact_ error text and _the line_ where the error occurs... **`:(`** – Aacini Mar 29 '18 at 13:36
  • Ah yes that was my bad I do apologize, however your latest attempt worked flawlessly, I can't thank you enough :) – WaleeK Mar 29 '18 at 15:08
1

Here is a "general" increment function for MS-Dos/Win98. The digits of the value has to be seperated by commas. The result will be stored in the same variable and in a secondary variable for printing (without the commas).
This solution could be extended to solve any arithmetic calculation.

@echo off
if not "%1" == "" goto %1

set counter=0

:loop
call %0 :inc counter print_cnt
echo counter=%print_cnt%
goto :loop
goto :eof

REM *************************************
:inc
set _self=%0
set _counterVar=%2
set _counterPrintVar=%3
set _rev=
set _result=
set _printResult=
set _carry=1
call %_self% :GetIndirectVar _counter %_counterVar%
call %_self% :reverse %_counter%
set %_counterVar%=%_result%
set %_counterPrintVar%=%_printResult%
goto :eof

REM *************************************
:GetIndirectVar
for %%a in (%3) do echo set %2=%%%%a%% > tmp.bat
call tmp.bat
del tmp.bat
goto :eof

REM *************************************
:reverse
if "%2" == "" goto :_add_start
set _rev=%2,%_rev%
shift
goto :reverse

:_add_start
for %%a in (%_rev%) do call %_self% :add_digit %%a
if "%_carry%" == "0" goto :eof
set _digit=1
goto :_add_digit_end

REM *************************************
:add_digit
set _digit=%2
rem echo d=%2 carry=%_carry%
if "%_carry%" == "0" goto :_add_digit_end
set _carry=0

if "%_digit%" == "9" set _carry=1
if "%_digit%" == "9" set _digit=0
if "%_carry%" == "1" goto :_add_digit_end
if "%_digit%" == "8" set _digit=9
if "%_digit%" == "7" set _digit=8
if "%_digit%" == "6" set _digit=7
if "%_digit%" == "5" set _digit=6
if "%_digit%" == "4" set _digit=5
if "%_digit%" == "3" set _digit=4
if "%_digit%" == "2" set _digit=3
if "%_digit%" == "1" set _digit=2
if "%_digit%" == "0" set _digit=1

:_add_digit_end
set _result=%_digit%,%_result%
set _printResult=%_digit%%_printResult%
goto :eof

:eof

You can also use it as an "external" increment function, you only have to name it "increm.bat"

@echo off
set myCounterA=9,9
call increm.bat :inc myCounterA output
echo The new value is %output%
jeb
  • 78,592
  • 17
  • 171
  • 225
  • I tried your approach, however it goes like counter=1 counter=112 1113 1114 and so on till it runs out of space at something like 10^24 or so.. – WaleeK Mar 29 '18 at 11:16
  • I've just retested it and it works, but I suppose you have somewhere a trailing space like `set _carry=0`, that would destroy the function – jeb Mar 30 '18 at 08:42