【问题标题】:How to get the sum of 2 numbers in original DOS?如何在原始DOS中获得2个数字的总和?
【发布时间】:2019-06-07 00:08:38
【问题描述】:

我想重温旧时的怀旧之情。
我一直在测试一些批处理命令,但我注意到 /a 在 dos 中不可用。
有没有另一种方法可以添加两个变量而不包括/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"

【问题讨论】:

  • 正在运行什么版本的 Windows 或 DOS?
  • 很久以前,但是当我没记错的时候,DOS中也没有set /p

标签: batch-file dos


【解决方案1】:

这比使用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 不支持ELSE

    解决方法:

     IF %1==b echo It is equal
     IF NOT %1==b echo It isn't equal
    
  2. 只有goto 可以跳转到一个标签,CALL 只能开始另一个批次。

    解决方法:

    将这样的内容放入批处理的第一行

     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. 没有代码块,比如

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

    解决方法:

     FOR %%a in (1 2 3 ) do CALL %0 :myFunc %%a
    
  4. 没有变量的间接扩展

    解决方法:

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

【讨论】:

  • @aschipfl 谢谢,但它似乎是 MsDos6.22 中唯一的 string handling,它不能从字符串中拆分分隔符,例如 ,;=<Space>。我添加了一些其他限制和可能的解决方法
【解决方案2】:

如果您尝试从实际的 DOS(而不是 32 位时代的 Windows 仿真)执行此操作,那根本不可能,除非您手动处理您可以作为输入的每一对可能的数字(这变得难以管理当你超过个位数时)。

这一直是 DOS 批处理文件的一大缺陷,通常通过调用实际脚本语言(如 BASIC)中的小脚本来弥补,通常由调用它们的同一个 .bat 文件写出。当然,这需要为您选择的语言配备口译员。

【讨论】:

  • 恕我直言,一个表示“你不能那样做”的“答案”不是一个好的答案,几乎没有评论...... :(
  • @Aacini “您的问题没有解决方案”是最好的答案。评论并不意味着持久(政策一直是它们可能随时被删除,即使它们通常不是),并且“你不能这样做”真的这里的答案.特别是,考虑到我们谈论的是二十多年前停产的操作系统,答案不会改变,因此“你可以做到”不仅是现在唯一有效的答案,而且是永远唯一有效的答案。 “没有解决方案”一个答案;它与“我不知道”或“不推荐”完全不同。
【解决方案3】:

这是尽可能接近的。鉴于主脚本名为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
  • @RossRidge, lang-doslang-cmd 似乎可以识别一些命令;但我使用它的主要原因是突出显示“字符串”和//备注,我觉得这很方便......
  • @RossRidge lang-dos 确实不受支持,这将使其使用默认荧光笔Is there syntax highlighting for DOS command line operations or DOS batch files?lang-vb 或有时 lang-bash 是批处理文件的更好选择
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-10
  • 2023-03-13
  • 2013-04-22
  • 2022-06-11
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多