在批处理菜单中混合 "goto" 和 "call" 命令的真实 DOS 中的问题

Problems in real DOS with mixed "goto" and "call" commands in a batch menu

我正在 MS-DOS 6.22 中创建批处理菜单,我需要将 if errorlevelgotocall 命令混合使用。我的订单有一些问题,因为它们没有按预期执行。
我无法在不使用 call 的情况下启动其他批处理文件,但 file6.bat 除外,因为我需要保留环境变量。

这是菜单示例:

:MENU
@echo off
echo [1] Choice 1
echo [2] Choice 2
echo [3] Choice 3
echo [4] Choice 4
echo [5] Choice 5
echo [6] Choice 6
echo [7] Choice 7
echo [8] Choice 8
echo [Y] Choice Y
echo [Z] Choice Z
choice /c12345678YZ /n /m "Select an option"

if errorlevel 10 call file7.bat
if errorlevel 9 file6.bat
if errorlevel 8 call file5.bat
if errorlevel 7 call file4.bat
if errorlevel 6 call file3.bat
if errorlevel 5 call file2.bat
if errorlevel 4 goto menu3
if errorlevel 3 goto menu2
if errorlevel 2 goto menu1
if errorlevel 1 call file1.bat

这就是行为:

你能帮我了解一下如何解决这个问题吗?

这里有三个重要事实:

    MS-DOS 6.22 的
  1. COMMAND.COM 从批处理文件的顶部到底部逐行处理,除了命令 GOTO 是用于继续批处理文件处理,不是在下一行,而是在标签指定为命令参数的行下面的行 GOTO.

  2. DOS 命令处理器 继续 在另一个批处理文件上处理一个批处理文件,如果另一个批处理文件 return 永远不会返回到当前批处理文件未使用命令 CALL.

  3. 在命令行上指定批处理文件
  4. 条件if errorlevel X表示IF ERRORLEVEL IS GREATER OR EQUAL 1。有必要使用两个条件来检查命令或应用程序的退出代码是否等于特定数字。必要的语法是:if errorlevel X if not errorlevel X+1 command。这就像 IF ERRORLEVEL IS EQUAL X 因为 ERRORLEVEL 必须 GREATER OR EQUAL X AND LESS THAN X+1。这两个条件只有 IF ERRORLEVEL IS EQUAL X 成立。示例:if errorlevel 6 if not errorlevel 7 call file3.bat 导致仅调用 file3.bat IF ERRORLEVEL IS EQUAL 6.

让我们一起看看用户按下的键所定义的用例。

用例 1: 用户按下键 Z.

  1. CHOICE.COM 退出,值 10 分配给 ERRORLEVEL
  2. 第一个条件 if errorlevel 10true,因此批处理文件 file7.bat 被命令处理器 调用
  3. COMMAND.COM 在完成 file7.bat 的处理后继续下一个 IF 条件行,除了它包含命令 EXIT 这导致在真正执行时退出独立于调用层次结构的命令进程。
  4. 第二个条件 if errorlevel 9 评估 不是 CHOICE.COM 的退出代码,而是批处理文件 return 编辑的退出代码 file7.bat 到主批处理文件。由 file7.bat 编辑的退出代码 return 很可能是 0,因此第二个条件和以下所有其他条件的计算结果为 false.

用例 2: 用户按下键 Y.

  1. CHOICE.COM 退出,值 9 分配给 ERRORLEVEL
  2. 第一个条件if errorlevel 10false
  3. 第二个条件 if errorlevel 9true,导致执行 file6.bat。这里没有使用命令CALL。因此,COMMAND.COM 在完成 file6.bat 的处理后不会 return 返回主批处理文件。出于这个原因,if errorlevel 9 file6.bat 以下的所有内容在 true 的条件下都无关紧要,因为批处理文件处理以 file6.bat.
  4. 的完成处理结束

用例 3: 用户按下键 8.

  1. CHOICE.COM 退出,值 8 分配给 ERRORLEVEL
  2. 第一个条件if errorlevel 10false
  3. 第二个条件if errorlevel 9false.
  4. 第三个条件 if errorlevel 8true,因此批处理文件 file5.bat 被命令处理器 调用
  5. COMMAND.COM 在完成 file5.bat 的处理后继续下一个 IF 条件行,除了它包含命令 EXIT 并且它也被执行了。
  6. 第四个条件 if errorlevel 7 评估退出代码 return 由批处理文件 file5.bat 编辑到最有可能 0 的主批处理文件,因此这第四个条件以及以下所有其他评估结果为 false.

用户按下键 765[=232 时的行为大致相同=].

用例 4: 用户按下键 4.

  1. CHOICE.COM 退出,值 4 分配给 ERRORLEVEL
  2. 前六个条件全部计算为false
  3. 第七个条件 if errorlevel 4true 因此执行命令 GOTO 导致继续批处理文件处理带有标签 menu3 的行下方的行。因此其他 IF 条件在此用例中无关紧要。

用户按下键 32.

时的行为大致相同

用例 5: 用户按下键 1.

  1. CHOICE.COM 退出,值 1 分配给 ERRORLEVEL
  2. 前九个条件全部评估为false
  3. 最后一个条件 if errorlevel 9true,因此批处理文件 file1.bat 被命令处理器 调用
  4. COMMAND.COM在处理完file1.bat后继续上线,除了EXIT命令在处理file1.bat的过程中被执行。

此代码至少存在三个潜在问题:

  1. 调用批处理文件的已执行命令或应用程序的最后退出代码决定了主批处理文件中的处理行为。这不是这里真正想要的。
  2. 如果 调用的 批处理文件中的 none 修改了 ERRORLEVEL 的值,就像只包含一系列 set variable=value, IF 条件下的 IF 条件导致调用另一个批处理文件也是 true这导致再调用一个批处理文件或继续对 menu3.
  3. 的代码进行批处理文件处理
  4. 最后一个条件下面的代码 if errorlevel 1 确定在所有这些批处理文件退出的情况下,从这个主批处理文件中调用 调用 的任何其他批处理文件接下来会发生什么值为 0.

第三个问题可以通过在最后一个条件之后在主批处理文件中写入 next 来轻松解决 if errorlevel 1 或者 goto MENU 在顶部继续批处理文件处理并再次打印菜单或 goto ENDBAT 主批处理文件的最后一行 :ENDBAT 继续处理批处理文件末尾的批处理文件,这意味着完成此批处理文件的处理。

但对于潜在问题 1 和 2,有必要确保主批处理文件的处理在调用其他批处理文件后不在下一个命令行继续,而是在菜单中继续处理。

@echo off
:MainMenu
cls
echo [1] Choice 1
echo [2] Choice 2
echo [3] Choice 3
echo [4] Choice 4
echo [5] Choice 5
echo [6] Choice 6
echo [7] Choice 7
echo [8] Choice 8
echo [Y] Choice Y
echo [Z] Choice Z
choice /C:12345678YZ /N /M "Select an option:"

if errorlevel 10 set BatFile=7
if errorlevel 9 if not errorlevel 10 file6.bat
if errorlevel 8 if not errorlevel 9 set BatFile=5
if errorlevel 7 if not errorlevel 8 set BatFile=4
if errorlevel 6 if not errorlevel 7 set BatFile=3
if errorlevel 5 if not errorlevel 6 set BatFile=2
if errorlevel 4 if not errorlevel 5 goto Menu3
if errorlevel 3 if not errorlevel 4 goto Menu2
if errorlevel 2 if not errorlevel 3 goto Menu1
if errorlevel 1 if not errorlevel 2 set BatFile=1

call file%BatFile%.bat
set BatFile=
goto MainMenu

:Menu3
echo Here would be shown menu 3.
goto ENDBAT

:Menu2
echo Here would be shown menu 2.
goto ENDBAT

:Menu1
echo Here would be shown menu 1.
goto ENDBAT

:ENDBAT

每个调用批处理文件的目标是在处理完调用的批处理文件后继续再次显示主菜单。出于这个原因,定义一个像 BatFile 这样的环境变量就足够了,其中包含要调用的批处理文件的编号,并确保始终只有一个 IF 条件是 true 根据 errorlevelCHOICE.COM 设置。

上面的代码导致在用户按下键 Y 时执行 file6.bat,而忽略此主批处理文件中的其余行。在子菜单 1 的适当代码上按 234 继续批处理文件处理, 2 or 3. 但对于键 1, 5 to 8 and 7 称为 适当的批处理文件,然后定义的环境变量 BatFile 未定义,批处理文件处理继续并再次打印主菜单并让用户使用多一个选择。

当然也可以将要调用的批处理文件的完整文件名分配给环境变量BatFile,而不仅仅是它的编号,如果要调用的批处理文件具有不同的文件名并且只是文件扩展名是所有要调用的批处理文件都一样。在这种情况下,带有 CALL 的命令行将是 call %BatFile%.bat.