如何在原始DOS中获得2个数字的总和?

5

我想重温好旧的DOS时光。
我试过几个批处理命令,但是我发现在DOS中无法使用/a
是否有其他方法可以用来添加两个变量而不包括/a

@echo off
::this is how I would originally add two numbers
set /p number1=
set /p number2=
set /a "number1=number1+number2"
echo %number1%
pause >nul
exit

当我运行这个程序时,DOS 状态会显示 "invalid switch. - /a"

3
你正在运行哪个版本的Windows或DOS? - jrcs3
5
很久以前,但我记得没错的话,在DOS中也没有set /p这个命令。 - Stephan
3个回答

4

这比使用set /a要棘手一些,但可以通过MS-DOS 6.22来解决。

一个部分是编写一个函数来添加单个数字,另一个函数可以添加多个数字。

主要问题是将数字拆分为单个数字,因为MS-DOS不支持字符串操作。
但在FOR-Loop处理中存在一个微小的缺陷,/将文本分成三个部分。

for %%a in (`abcdef/ghijklmno`) do echo %%a

输出

abcdef
g
hijklmno
使用这个技巧可以将数字拆分成单个数字。 split.bat
@echo off
for %%P in (/%1.) do if %%P==: goto %1

set _idx=
set _remain=%2
set _splitRev=
set _splitRev_comma=

:loop

set _loop=1

for %%a in (/%_remain%) do call %0 :split %1 %%a
if NOT "%_remain%"=="" goto :loop
set %1=%_splitRev%
set %1_comma=%_splitRev_comma%

REM Clear temp vars
FOR %%v in (_remain _idx _loop _splitRev _splitRev_comma) do set %%v=
goto :eof

:split
if %_loop%%==2 goto :split_2
set _loop=2
set _remain=
set _splitRev=%3%_splitRev%
set _splitRev_comma=%3,%_splitRev_comma%
goto :eof

:split_2
set _remain=%3
goto :eof

:eof

add.bat 看起来像这样:

@echo off
for %%P in (/%1.) do if %%P==: goto %1

call split _valueRev1 %1
call split _valueRev2 %2

set _result=
set _carry=
for %%d in (%_valueRev1_comma%,0,0,0,0,0) do call %0 :getDig1 %%d


REM Remove leading zeros
:zeroLoop
for %%z in (/%_result%) do set _remain=%%z
if not %_result%==0%_remain% goto :finish
set _result=%_remain%
goto :zeroLoop

:finish
echo %1+%2=%_result%

REM Clear temp vars
FOR %%v in (_result _carry _len _digit1 _digit2 _remain _valueRev1 _valueRev1_comma _valueRev2 _valueRev2_comma) do set %%v=
goto :eof

:getDig1
set _digit1=%2
set _digit2=
for %%d in (/%_valueRev2%0) do call %0 :getDig2 %%d

set _len=%_carry%
call %0 :lenAddDigit %_digit1%
call %0 :lenAddDigit %_digit2%
call %0 :len2val
set _result=%_val%%_result%
goto :eof

:getDig2
if not "%_digit2%"==" set _valueRev2=%2
if "%_digit2%"=="" set _digit2=%2
goto :eof

:lenAddDigit
if %2==1 set _len=%_len%#
if %2==2 set _len=%_len%##
if %2==3 set _len=%_len%###
if %2==4 set _len=%_len%####
if %2==5 set _len=%_len%#####
if %2==6 set _len=%_len%######
if %2==7 set _len=%_len%#######
if %2==8 set _len=%_len%########
if %2==9 set _len=%_len%#########
goto :eof

:len2val
set _carry=
set _val=
if %_len%.==. set _val=0
if %_len%.==. goto :eof
if %_len%==# set _val=1
if %_len%==## set _val=2
if %_len%==### set _val=3
if %_len%==#### set _val=4
if %_len%==##### set _val=5
if %_len%==###### set _val=6
if %_len%==####### set _val=7
if %_len%==######## set _val=8
if %_len%==######### set _val=9
if NOT "%_val%"=="" goto :eof
set _carry=#

if %_len%==########## set _val=0
if %_len%==########### set _val=1
if %_len%==############ set _val=2
if %_len%==############# set _val=3
if %_len%==############## set _val=4
if %_len%==############### set _val=5
if %_len%==################ set _val=6
if %_len%==################# set _val=7
if %_len%==################## set _val=8
if %_len%==################### set _val=9
goto :eof

:eof

在MS-DOS 6.22(VMWare)上成功测试

#MS-DOS 6.22的限制

  1. IF doesn't support ELSE

    Workaround:

     IF %1==b echo It is equal
     IF NOT %1==b echo It isn't equal
    
  2. Only goto can jump to a label, CALL can only start another batch.

    Workaround:

    Put something like this into the first line of your batch

     FOR %%P in (/%1) do IF %%P==: goto %1
     ...
     REM This calls the current batch file and jumps to a label
     CALL %0 :myLabel arg1
     ...
     :myLabel
     echo arg1=%2
     echo Action1
     echo Action2
     goto :eof
    
  3. No code blocks, like

     FOR %%a in (1 2 3 ) do ( 
       set concat=%%a
       echo %concat%
     )
    

    Workaround:

     FOR %%a in (1 2 3 ) do CALL %0 :myFunc %%a
    
  4. No indirect expansion of variables

    Workaround:

     set var=content
     set indirect=var
      > temp$$$.bat echo set result=%%%indirect%%%
     call temp$$$.bat
     echo result=%result%
    

@aschipfl 谢谢,但这似乎是 MsDos6.22 中唯一的 字符串处理,它无法从字符串中分离分隔符,比如 ,;=<空格>。我添加了一些其他限制和可能的解决方法。 - jeb

3

如果您试图从实际的DOS中执行此操作(而不是来自32位时代的Windows仿真),那么除非您手动处理输入可能具有的每对数字(当您超过单个数字时,这将变得难以管理),否则根本不可能。

这在DOS批处理文件中始终是一个重大缺陷,通常通过调用实际脚本语言(例如BASIC)中的小型脚本来解决,这些脚本经常由调用它们的相同.bat文件编写。当然,这需要您选择的语言的解释器。


在我看来,一个表明“你不能这样做”的“答案”并不是一个好的回答,仅仅是一条评论... :( - Aacini
4
@Aacini的回答:“你的问题没有解决方案”已经是最好的答案了。评论并不是永久的(即使它们通常不会被删除,政策始终是它们可以随时被删除),“你不能那样做”确实是这里的答案。特别是考虑到我们正在谈论的操作系统已经停产超过20年,答案不会改变,因此“你可以那样做”不仅是现在唯一有效的答案,而且是永远唯一有效的答案。“没有解决方案”就是一个答案;它与“我不知道”或“不推荐”完全不同。 - aaaaaa123456789

1
这是我能做到的最接近的翻译。由于主脚本名为sum.bat,请将两个数字作为命令行参数提供。
以下是sum.bat的代码:
@echo off & > nul ver
rem // Define constants here:
set SUB=.\sum-sub.bat
set FILE=.\sum.tmp
set RESULT=.\sum-res.tmp
rem // Check if enough arguments are provided:
if "%2"=="" (>&2 echo ERROR: too few arguments!) & < nul find "" & goto :END
rem // Initialise variables:
set LIST=
rem // Create list of as many space-separated `#` symbols as given by 1st number:
call %SUB% %1
rem // Append list by as many space-separated `#` symbols as given by 2nd number:
call %SUB% %2
rem // Terminate execution in case of unsupported numbers:
if ErrorLevel 1 goto :END
rem // Create empty temporary file:
> nul copy /Y nul %FILE%
rem // Fill temporary file with as many bytes as list items are given:
for %%I in (%LIST%) do (> nul copy /B %FILE% + nul %FILE% /A)
rem // Get size of temporary file, filter out first summary line and store in file:
dir /A:-D /-W /-C %FILE% | find "1 File(s)" > %RESULT%
rem /* Read from file the summary line but display it without "1 File(s)" prefix;
rem    since this is searched literally, the code becomes language-dependent;
rem    the "bytes" suffix unfortunately remains: */
< %RESULT% (
    for %%I in (# # # # # # # # # # # # # # # # # # # # # # # #) do > nul pause
    sort & echo/
)
rem // Clean up temporary files:
del %FILE% %RESULT%
:END

这是子程序sum-sub.bat的代码:
@echo off
rem // Jump to correct entry point to create/append a list with correct length:
2> nul goto :$%1 & < nul find "" & >&2 echo ERROR: unexpected argument!
rem // Do not add anything to the list upon errors:
goto :$0
rem /* Inverse list to add as many space-separated `#` symbols as given by the argument;
rem    extend it in the same manner in order to support numbers greater than `12`: */
:$12
set LIST=%LIST% #
:$11
set LIST=%LIST% #
:$10
set LIST=%LIST% #
:$9
set LIST=%LIST% #
:$8
set LIST=%LIST% #
:$7
set LIST=%LIST% #
:$6
set LIST=%LIST% #
:$5
set LIST=%LIST% #
:$4
set LIST=%LIST% #
:$3
set LIST=%LIST% #
:$2
set LIST=%LIST% #
:$1
set LIST=%LIST% #
:$0

这里是一些使用示例:
>>> sum.bat 1 0
             19 bytes

>>> sum.bat 3 6
              9 bytes

>>> sum.bat 2
ERROR: to few arguments!

>>> sum.bat 1 0
             19 bytes

>>> sum.bat 13 4
ERROR: unexpected argument!
我必须承认,我在Windows命令提示符中测试了这种方法,但没有在真正的MS-DOS环境中测试过。

我认为 lang-dos 不是代码美化器支持的已知语言。无论如何,它没有正确地突出显示您的代码,所以我认为您最好使用 lang-none - Ross Ridge
@RossRidge,lang-doslang-cmd似乎能够识别一些命令;但我使用它的主要原因是它可以突出显示“字符串”和//注释,我觉得这非常方便... - aschipfl
1
@RossRidge,“lang-dos”确实不受支持,这将使其使用默认的高亮显示器是否有DOS命令行操作或DOS批处理文件的语法突出显示?。对于批处理文件,lang-vb或有时lang-bash是更好的选择。 - phuclv

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