46

I've spent the past 3hrs trying to work this out but just couldn't find a solution. Here's my batch script:

if NOT Exist Counter.txt GOTO START
Type c:\counter.txt
if %COUNTER% EQU %Cycles% goto Pass
if NOT %COUNTER% EQU %Cycles% goto Cycle

:START
Set COUNTER=0
set CYCLES=250

:Cycle
set /A COUNTER=%COUNTER%+1     <----------- PROBLEM
echo Iteration %COUNTER% of %CYCLES%
echo Delay 3 seconds to reboot
choice /cy /n /t:y,3
warmboot.com

:Pass
pause

What it's doing is it runs the file "warmboot.com" (which reboots my PC) and runs for 250 cycles. Once the cycles have run 250 times (i.e when counter equals cycles) then it stops.

Under Windows, this works. However, this doesn't work under DOS environment. I've tried versions from v4 all the way up to v6.22 and even v7 and they all fail when it reaches the "PROBLEM" line.

If I do this:

set /A COUNTER=%COUNTER%+1
echo %Counter%

OR this:

set /A COUNTER+=1
echo %Counter%

both will return a blank line, i.e it shows nothing as the output.

If I type:

set /?

then it shows this:

Displays, sets, or removes cmd.exe environment variables.

SET [variable=[string]]

variable Specifies the environment-variable name.
string Specifies a series of characters to assign to the variable.

but typing the same command under CMD in Windows shows a lot more stuff. I'm thinking that the SET function under DOS doesn't support arithmetic functions, but for work purposes I have to run my scripts in DOS only.

Any ideas?

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
shadowz1337
  • 710
  • 1
  • 8
  • 21
  • 1
    I'm *pretty* sure plain DOS can't do this. Write an actual program instead (there are plenty of languages to choose from, e.g. [Turbo Pascal](http://edn.embarcadero.com/article/20803) or [C](http://www.delorie.com/djgpp/), maybe even QBasic). – Michael Madsen Feb 11 '14 at 09:11
  • 2
    @Michael Madsen, I'm unfamiliar with those languages and for my job requirements I have to run the batch script in DOS. – shadowz1337 Feb 11 '14 at 09:23
  • 1
    Good old times... Wasn't there a BASIC delivered with DOS? If I remember correctly, it was only one EXE, and it was quite small (below 1 MB?) – Stephan Feb 11 '14 at 09:24
  • @shadowz1337: Does your job requirements *explicitly* state it has to be a *batch script*, or just that it has to run in DOS? All of the compilers/languages I mention run in plain 16-bit DOS, and there is *very little* to learn in order to make a program like this. – Michael Madsen Feb 11 '14 at 09:34
  • lines 1 and 2 will work in MSDos. Lines 3 and 4 will give you syntax errors. Are you sure you are using MSDos? – foxidrive Feb 11 '14 at 10:05

9 Answers9

77

I realize you've found another answer - but the fact is that your original code was nearly correct but for a syntax error.

Your code contained the line

set /A COUNTER=%COUNTER%+1

and the syntax that would work is simply...

set /A COUNTER=COUNTER+1

See http://ss64.com/nt/set.html for all the details on the SET command. I just thought I'd add this clarification for anyone else who doesn't have the option of using FreeDOS.

Furr
  • 835
  • 6
  • 3
  • 5
    This answer is wrong, as the question is explicitly about pure MS-DOS, not about cmd.exe. – jeb Jun 29 '16 at 08:03
  • 3
    it's even more wrong, as `set /a var=%var%+1` works fine (although not recommended) – Stephan Jun 13 '18 at 09:22
  • 5
    @niico Because the example in this answer works on the modern versions of Windows that most people actually use today. It's not correct answer for the question that was actually asked, but it's a correct answer for people who want to know how to increment a variable on a modern version of Windows. – Ross Ridge Jan 05 '20 at 07:03
  • if you find in for loop the variable not increment, see https://stackoverflow.com/questions/34600979/why-wont-this-increment-work-in-batch – yu yang Jian Jan 14 '22 at 15:32
7

Indeed, set in that old DOS (rather than Windows' cmd) has no option to allow for arithmetic. (cmd does have the way you described.) You could do a giant lookup table, though:

if %COUNTER%==249 set COUNTER=250
...
if %COUNTER%==3 set COUNTER=4
if %COUNTER%==2 set COUNTER=3
if %COUNTER%==1 set COUNTER=2
if %COUNTER%==0 set COUNTER=1
Joey
  • 344,408
  • 85
  • 689
  • 683
  • 2
    Hmm is there an easier way? The 250 cycles was just an example, I actually need to run it for over 3000 times..... – shadowz1337 Feb 11 '14 at 09:16
  • 2
    I know this is old now, but I've just done something along these lines and I should mention that the correct code is `if %COUNTER%==1` ... – Grim... May 05 '15 at 12:14
  • There should be a more elegant way – K.Mulier Jun 28 '16 at 16:44
  • 2
    @K.Mulier: We're talking about the shell in a home user operating system from the 80s. Batch files were good for little more than executing a number of commands in sequence, not arithmetic. – Joey Jun 28 '16 at 21:22
  • Hi @Joey , you are right. I'm sorry for the downvote. Just converted it into an upvote ;-) – K.Mulier Jun 29 '16 at 08:32
  • Joey's way for building your own arithmetic is good, but you don't need to build such a big lookup table. – jeb Jun 30 '16 at 17:05
4

A little bit late for the party, but it's an interessting question.

You can write your own inc.bat for incrementing a number.
It can increment numbers from 0 to 9998.

@echo off
if "%1"==":inc" goto :increment

call %0 :inc %counter0%
set counter0=%_cnt%
if %_overflow%==0 goto :exit 

call %0 :inc %counter1%
set counter1=%_cnt%
if %_overflow%==0 goto :exit 

call %0 :inc %counter2%
set counter2=%_cnt%
if %_overflow%==0 goto :exit 

call %0 :inc %counter3%
set counter3=%_cnt%
goto :exit

:increment
set _overflow=0
set _cnt=%2

if "%_cnt%"=="" set _cnt=0

if %_cnt%==9 goto :overflow
if %_cnt%==8 set _cnt=9
if %_cnt%==7 set _cnt=8
if %_cnt%==6 set _cnt=7
if %_cnt%==5 set _cnt=6
if %_cnt%==4 set _cnt=5
if %_cnt%==3 set _cnt=4
if %_cnt%==2 set _cnt=3
if %_cnt%==1 set _cnt=2
if %_cnt%==0 set _cnt=1
goto :exit

:overflow
set _cnt=0
set _overflow=1
goto :exit

:exit
set count=%counter3%%counter2%%counter1%%counter0%

A sample for using it is here

@echo off
set counter0=0
set counter1=
set counter2=
set counter3=

:loop
call inc.bat
echo %count%
if not %count%==250 goto :loop
jeb
  • 78,592
  • 17
  • 171
  • 225
2

I've found my own solution.

Download FreeDOS from here: http://chtaube.eu/computers/freedos/bootable-usb/

Then using my Counter.exe file (which basically generates a Counter.txt file and increments the number inside every time it's being called), I can assign the value of the number to a variable using:

Set /P Variable =< Counter.txt

Then, I can check if it has run 250 cycles by doing:

if %variable%==250 echo PASS

BTW, I still can't use Set /A since FreeDOS doesn't support this command, but at least it supports the Set /P command.

shadowz1337
  • 710
  • 1
  • 8
  • 21
1

I didn't use DOS for - puh - feels like decades, but based on an old answer and my memories, the following should work (although I got no feedback, the answer was accepted, so it seems to work):

@echo off
  REM init.txt should already exist
  REM to create it:
  REM   COPY CON INIT.TXT
  REM   SET VARIABLE=^Z
  REM ( press Ctrl-Z to generate ^Z )
  REM
  REM also the file "temp.txt" should exist.
REM add another "x" to a file:
echo x>>count.txt
REM count the lines in the file and put it in a tempfile:
type count.txt|find /v /c "" >temp.txt

REM join init.txt and temp.txt to varset.bat:
copy init.txt+temp.txt varset.bat
REM execute it to set %variable%:
call varset.bat

for %%i in (%variable%) do set numb=%%i
echo Count is: %numb%
   REM just because I'm curious, does the following work? :
   set numb2=%variable%
   echo numb2 is now %var2%
if %numb%==250 goto :finished
echo another boot...
warmboot.exe
:finished
echo that was the last one.

In DOS, neither set /a nor set /p exist, so we have to work around that. I think both for %%i in (%variable%) do set numb=%%i and set numb2=%variable% will work, but I can't verify.

WARNING: as there is no ">" or "<" comparison in DOS, you should delete the batchfile at the :finished label (because it continues to increment and 251 is not equal 250 anymore)

(PS: the basic idea is from here. Thanks foxidrive. I knew, I knew it from StackOverflow but had a hard time to find it again)

Community
  • 1
  • 1
Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Interessting solution, I tested it and it works, but you should add `>nul` to `copy init.txt+temp.txt varset.bat` to avoid the copy texts. It's also a bit slow,as it gets slower and slower for bigger values. – jeb Jul 03 '16 at 19:19
  • @jeb Thanks for the feedback (I have no DOS to test). Yes, it gets slower, but I don't think it matters as long as something like a reboot is involved. Also this might be a - hmm - suboptimal solution when the counter gets into the ten-thousands. – Stephan Jul 03 '16 at 20:41
1

Coming to the party very very late, but from my old memory of DOS batch files, you can keep adding a character to the string each loop then look for a string of that many of that character. for 250 iterations, you either have a very long "cycles" string, or you have one loop inside using one set of variables counting to 10, then another loop outside that uses another set of variable counting to 25.

Here is the basic loop to 30:

@echo off
rem put how many dots you want to loop
set cycles=..............................
set cntr=
:LOOP
set cntr=%cntr%.
echo around we go again
if "%cycles%"=="%cntr%" goto done
goto loop
:DONE
echo around we went
GadgetGuy
  • 439
  • 1
  • 4
  • 8
0

I built my answer thanks to previous contributors.

Not having time for a custom counter.exe, I downloaded sed for FREEDOS.

And then the batch code could be, emulating "wc -l" with the utility sed, something like this according to your loop (I just use it to increment through executions starting from "1" to n+1):

Just remember to manually create a file "test.txt" with written on the first row

0


sed -n '$=' test.txt > counter.txt
set /P Var=< counter.txt
echo 0 >> test.txt
Inatna
  • 19
  • 1
0

Directly from the command line:

 for /L %n in (1,1,100) do @echo %n

Using a batch file:

 @echo off
 for /L %%n in (1,1,100) do echo %%n

Displays:

 1
 2
 3
 ...
 100
Niente0
  • 504
  • 3
  • 11
  • 5
    The question is about MS-DOS not cmd.exe under Windows. So your solution can't work – jeb Nov 07 '16 at 22:37
-1

None of these seemed to work for me:

@ECHO OFF

REM 1. Initialize our counter
SET /A "c=0"

REM Iterate through a dummy list. 
REM Notice how the counter is used: "CALL ECHO %%c%%" 
FOR /L %%i in (10,1,20) DO (

  REM 2. Increment counter
  SET /A "c+=1"

  REM 3. Print our counter "%c%" and some dummy data "%%i"
  CALL ECHO Line %%c%%: - Data: %%i
)

The answer was extracted from: https://www.tutorialspoint.com/batch_script/batch_script_arrays.htm (Section: Length of an Array)

Result:

Line 1: - Data: 10
Line 2: - Data: 11
Line 3: - Data: 12
Line 4: - Data: 13
Line 5: - Data: 14
Line 6: - Data: 15
Line 7: - Data: 16
Line 8: - Data: 17
Line 9: - Data: 18
Line 10: - Data: 19
Line 11: - Data: 20
Kibonge Murphy
  • 1,140
  • 8
  • 9
  • 1
    The question is about MS-DOS not cmd.exe under Windows. So your solution can't work. There were no `FOR /L` neither a `set /a` in the old days – jeb Nov 23 '20 at 10:40