如何在DOS下增加变量?

51

我花了过去的三个小时试图解决这个问题,但是无法找到解决方案。以下是我的批处理脚本:

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

它所做的是运行文件"warmboot.com"(可以重新启动我的电脑)并运行250个循环。一旦循环运行了250次(即当计数器等于循环次数时),它就停止。

在Windows下,这个程序可以正常工作。然而,在DOS环境下,它无法正常工作。我尝试过v4到v6.22甚至v7版本,但它们都在"PROBLEM"这一行失败了。

如果我这样做:

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

或者这个:

set /A COUNTER+=1
echo %Counter%

两者都会返回一个空行,即不会显示任何输出。

如果我输入:

set /?

然后它显示如下内容:

显示、设置或删除cmd.exe环境变量。

SET [variable=[string]]

variable指定环境变量名称。
string指定要分配给该变量的一系列字符。

但在Windows的CMD下输入相同的命令会显示更多东西。我认为DOS下的SET功能不支持算术函数,但出于工作目的,我必须仅在DOS中运行我的脚本。

有任何想法吗?


1
我相当确定纯DOS无法做到这一点。最好编写一个真正的程序(有很多语言可供选择,例如Turbo Pascal或C,甚至可能是QBasic)。 - Michael Madsen
2
@Michael Madsen,我不熟悉那些编程语言,而我的工作要求我在DOS中运行批处理脚本。 - shadowz1337
1
好旧的时光...DOS不是附带了BASIC吗?如果我没记错的话,那只有一个EXE文件,而且非常小(不到1 MB?) - Stephan
@shadowz1337:你的工作要求是否明确规定必须是批处理脚本,还是只需要在DOS中运行?我提到的所有编译器/语言都可以在纯16位DOS中运行,而且学习成本非常低,制作这样的程序几乎没有什么难度。 - Michael Madsen
第1行和第2行将在MSDos中工作。第3行和第4行将给您语法错误。您确定正在使用MSDos吗? - foxidrive
9个回答

82

我知道你已经找到了另一个答案,但事实上,你原来的代码基本正确,只是有一个语法错误。

你的代码包含以下行:

set /A COUNTER=%COUNTER%+1

可以使用的语法非常简单,只需要...

set /A COUNTER=COUNTER+1

查看 http://ss64.com/nt/set.html 获取 SET 命令的所有细节。我只是想为那些无法使用 FreeDOS 的人添加这一说明。


5
这个答案不正确,因为问题明确指的是纯MS-DOS,而不是cmd.exe。 - jeb
3
“set /a var=%var%+1”虽然不建议使用,但它可以正常工作。如果使用其他方法,则会更加错误。 - Stephan
5
因为这个答案中的示例适用于大多数人今天实际使用的现代Windows版本。这不是针对实际提问的问题的正确答案,但对于想知道如何在现代Windows版本上增加变量的人来说,这是一个正确的答案。 - Ross Ridge
如果您在for循环中发现变量未增加,请参阅https://stackoverflow.com/questions/34600979/why-wont-this-increment-work-in-batch - yu yang Jian

7

实际上,在旧版DOS中(而不是Windows的cmd),set命令没有选项允许进行算术运算。(cmd命令确实可以使用您所描述的方法。)但您可以使用一个巨大的查找表:

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

2
嗯,有没有更简单的方法?250个循环只是一个例子,实际上我需要运行它超过3000次..... - shadowz1337
2
我知道这已经过时了,但我刚刚做了类似的事情,我应该提到正确的代码是 if %COUNTER%==1 ... - Grim...
应该有一种更优雅的方式。 - K.Mulier
2
@K.Mulier:我们正在谈论80年代家用操作系统中的shell。批处理文件只能用于按顺序执行一系列命令,而不能进行算术运算。 - Joey
嗨@Joey,你是对的。我很抱歉给你投了反对票。现在已经改成赞同了;-) - K.Mulier
Joey 的自制算法方式不错,但你并不需要构建如此大的查找表。 - jeb

4

虽然来晚了一点,但这是一个有趣的问题。

您可以编写自己的inc.bat文件来递增数字。
它可以将数字从0递增到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%

这里有一个使用它的示例。
@echo off
set counter0=0
set counter1=
set counter2=
set counter3=

:loop
call inc.bat
echo %count%
if not %count%==250 goto :loop

2
我找到了自己的解决方案。
从这里下载FreeDOS: http://chtaube.eu/computers/freedos/bootable-usb/ 然后使用我的Counter.exe文件(它基本上生成一个Counter.txt文件,并在每次调用时递增其中的数字),我可以使用以下命令将该数字的值分配给一个变量:
Set /P Variable =< Counter.txt

然后,我可以通过以下方式检查它是否已经运行了250个周期:
if %variable%==250 echo PASS

顺便说一句,由于FreeDOS不支持Set /A命令,所以我仍然无法使用它,但至少它支持Set /P命令。


1

我已经有好几十年没有使用DOS了,但根据一个旧的答案和我的记忆,以下内容应该可以工作(虽然我没有得到反馈,但答案被接受了,所以似乎可以工作):

@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.

在DOS中,既没有set /a也没有set /p,因此我们需要解决这个问题。我认为for %%i in (%variable%) do set numb=%%iset numb2=%variable%都可以工作,但我无法验证。
警告:由于DOS中没有">"或"<"比较符号,您应该删除:finished标签处的批处理文件(因为它继续递增,251不再等于250)。
(PS:基本思路来自here。感谢foxidrive。我知道,我在StackOverflow上知道它,但很难再次找到它)

有趣的解决方案,我测试过了,它可以工作,但你应该在 copy init.txt+temp.txt varset.bat 中添加 >nul 来避免复制文本。它也有点慢,对于更大的值,速度会变得越来越慢。 - jeb
@jeb 感谢您的反馈(我没有DOS进行测试)。是的,它会变慢,但只要涉及到像重新启动这样的操作,我认为这并不重要。此外,当计数器达到万位数时,这可能是一个次优解决方案。 - Stephan

1
来晚了,但根据我对DOS批处理文件的古老记忆,您可以在每次循环中添加一个字符到字符串中,然后查找那个字符的连续出现次数。250次迭代后,您可能会得到一个非常长的“循环”字符串,或者您可以在内部使用一组变量计数到10,然后在外部使用另一组变量计数到25。
以下是基本循环到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

0

我感谢之前的贡献者,帮助我构建了我的答案。

由于没有时间编写自定义的counter.exe程序,我下载了FREEDOS的sed

然后,使用实用程序sed模拟"wc -l",根据您的循环编写批处理代码,类似于以下内容(我只是使用它来从“1”到n+1递增执行):

请记得手动创建一个名为“test.txt”的文件,并在第一行上写下内容。

0


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

0

直接从命令行:

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

使用批处理文件:

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

显示:

 1
 2
 3
 ...
 100

5
这个问题涉及到MS-DOS,而不是Windows下的cmd.exe。因此,你提供的解决方案无法使用。 - jeb

-1

对我来说,这些都似乎不起作用:

@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
)

答案摘自:https://www.tutorialspoint.com/batch_script/batch_script_arrays.htm(章节:数组长度

结果:

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

1
这个问题是关于 MS-DOS 而不是 Windows 下的 cmd.exe。因此,你的解决方案行不通。在旧时代,没有 FOR /Lset /a - jeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接