在批处理菜单中混合 "goto" 和 "call" 命令的真实 DOS 中的问题
Problems in real DOS with mixed "goto" and "call" commands in a batch menu
我正在 MS-DOS 6.22 中创建批处理菜单,我需要将 if errorlevel
与 goto
和 call
命令混合使用。我的订单有一些问题,因为它们没有按预期执行。
我无法在不使用 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
这就是行为:
- 如果我选择 1,它会执行第 4 个 [
goto menu3
]。
- 如果我选择 2、3、4、5、Y 和 Z,它会正确响应。
- 如果我选择 6、7 和 8,什么也不会发生。
你能帮我了解一下如何解决这个问题吗?
这里有三个重要事实:
MS-DOS 6.22 的 COMMAND.COM
从批处理文件的顶部到底部逐行处理,除了命令 GOTO 是用于继续批处理文件处理,不是在下一行,而是在标签指定为命令参数的行下面的行 GOTO.
DOS 命令处理器 继续 在另一个批处理文件上处理一个批处理文件,如果另一个批处理文件 return 永远不会返回到当前批处理文件未使用命令 CALL.
在命令行上指定批处理文件
条件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.
CHOICE.COM
退出,值 10
分配给 ERRORLEVEL
。
- 第一个条件
if errorlevel 10
为 true,因此批处理文件 file7.bat
被命令处理器 调用。
COMMAND.COM
在完成 file7.bat
的处理后继续下一个 IF 条件行,除了它包含命令 EXIT 这导致在真正执行时退出独立于调用层次结构的命令进程。
- 第二个条件
if errorlevel 9
评估 不是 CHOICE.COM
的退出代码,而是批处理文件 return 编辑的退出代码 file7.bat
到主批处理文件。由 file7.bat
编辑的退出代码 return 很可能是 0
,因此第二个条件和以下所有其他条件的计算结果为 false.
用例 2: 用户按下键 Y.
CHOICE.COM
退出,值 9
分配给 ERRORLEVEL
。
- 第一个条件
if errorlevel 10
是false。
- 第二个条件
if errorlevel 9
为 true,导致执行 file6.bat
。这里没有使用命令CALL。因此,COMMAND.COM
在完成 file6.bat
的处理后不会 return 返回主批处理文件。出于这个原因,if errorlevel 9 file6.bat
以下的所有内容在 true 的条件下都无关紧要,因为批处理文件处理以 file6.bat
. 的完成处理结束
用例 3: 用户按下键 8.
CHOICE.COM
退出,值 8
分配给 ERRORLEVEL
。
- 第一个条件
if errorlevel 10
是false。
- 第二个条件
if errorlevel 9
为false.
- 第三个条件
if errorlevel 8
为 true,因此批处理文件 file5.bat
被命令处理器 调用。
COMMAND.COM
在完成 file5.bat
的处理后继续下一个 IF 条件行,除了它包含命令 EXIT 并且它也被执行了。
- 第四个条件
if errorlevel 7
评估退出代码 return 由批处理文件 file5.bat
编辑到最有可能 0
的主批处理文件,因此这第四个条件以及以下所有其他评估结果为 false.
用户按下键 7、6 或 5[=232 时的行为大致相同=].
用例 4: 用户按下键 4.
CHOICE.COM
退出,值 4
分配给 ERRORLEVEL
。
- 前六个条件全部计算为false。
- 第七个条件
if errorlevel 4
是 true 因此执行命令 GOTO 导致继续批处理文件处理带有标签 menu3
的行下方的行。因此其他 IF 条件在此用例中无关紧要。
用户按下键 3 或 2.
时的行为大致相同
用例 5: 用户按下键 1.
CHOICE.COM
退出,值 1
分配给 ERRORLEVEL
。
- 前九个条件全部评估为false。
- 最后一个条件
if errorlevel 9
为 true,因此批处理文件 file1.bat
被命令处理器 调用。
COMMAND.COM
在处理完file1.bat
后继续上线,除了EXIT命令在处理file1.bat
的过程中被执行。
此代码至少存在三个潜在问题:
- 调用批处理文件的已执行命令或应用程序的最后退出代码决定了主批处理文件中的处理行为。这不是这里真正想要的。
- 如果 调用的 批处理文件中的 none 修改了
ERRORLEVEL
的值,就像只包含一系列 set variable=value
, IF 条件下的 IF 条件导致调用另一个批处理文件也是 true这导致再调用一个批处理文件或继续对 menu3
. 的代码进行批处理文件处理
- 最后一个条件下面的代码
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 根据 errorlevel
由 CHOICE.COM
设置。
上面的代码导致在用户按下键 Y 时执行 file6.bat
,而忽略此主批处理文件中的其余行。在子菜单 1 的适当代码上按 2、3 或 4 继续批处理文件处理, 2 or 3. 但对于键 1, 5 to 8 and 7 被 称为 适当的批处理文件,然后定义的环境变量 BatFile
未定义,批处理文件处理继续并再次打印主菜单并让用户使用多一个选择。
当然也可以将要调用的批处理文件的完整文件名分配给环境变量BatFile
,而不仅仅是它的编号,如果要调用的批处理文件具有不同的文件名并且只是文件扩展名是所有要调用的批处理文件都一样。在这种情况下,带有 CALL 的命令行将是 call %BatFile%.bat
.
我正在 MS-DOS 6.22 中创建批处理菜单,我需要将 if errorlevel
与 goto
和 call
命令混合使用。我的订单有一些问题,因为它们没有按预期执行。
我无法在不使用 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
这就是行为:
- 如果我选择 1,它会执行第 4 个 [
goto menu3
]。 - 如果我选择 2、3、4、5、Y 和 Z,它会正确响应。
- 如果我选择 6、7 和 8,什么也不会发生。
你能帮我了解一下如何解决这个问题吗?
这里有三个重要事实:
-
MS-DOS 6.22 的
COMMAND.COM
从批处理文件的顶部到底部逐行处理,除了命令 GOTO 是用于继续批处理文件处理,不是在下一行,而是在标签指定为命令参数的行下面的行 GOTO.DOS 命令处理器 继续 在另一个批处理文件上处理一个批处理文件,如果另一个批处理文件 return 永远不会返回到当前批处理文件未使用命令 CALL.
在命令行上指定批处理文件
条件
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.
CHOICE.COM
退出,值10
分配给ERRORLEVEL
。- 第一个条件
if errorlevel 10
为 true,因此批处理文件file7.bat
被命令处理器 调用。 COMMAND.COM
在完成file7.bat
的处理后继续下一个 IF 条件行,除了它包含命令 EXIT 这导致在真正执行时退出独立于调用层次结构的命令进程。- 第二个条件
if errorlevel 9
评估 不是CHOICE.COM
的退出代码,而是批处理文件 return 编辑的退出代码file7.bat
到主批处理文件。由file7.bat
编辑的退出代码 return 很可能是0
,因此第二个条件和以下所有其他条件的计算结果为 false.
用例 2: 用户按下键 Y.
CHOICE.COM
退出,值9
分配给ERRORLEVEL
。- 第一个条件
if errorlevel 10
是false。 - 第二个条件
if errorlevel 9
为 true,导致执行file6.bat
。这里没有使用命令CALL。因此,COMMAND.COM
在完成file6.bat
的处理后不会 return 返回主批处理文件。出于这个原因,if errorlevel 9 file6.bat
以下的所有内容在 true 的条件下都无关紧要,因为批处理文件处理以file6.bat
. 的完成处理结束
用例 3: 用户按下键 8.
CHOICE.COM
退出,值8
分配给ERRORLEVEL
。- 第一个条件
if errorlevel 10
是false。 - 第二个条件
if errorlevel 9
为false. - 第三个条件
if errorlevel 8
为 true,因此批处理文件file5.bat
被命令处理器 调用。 COMMAND.COM
在完成file5.bat
的处理后继续下一个 IF 条件行,除了它包含命令 EXIT 并且它也被执行了。- 第四个条件
if errorlevel 7
评估退出代码 return 由批处理文件file5.bat
编辑到最有可能0
的主批处理文件,因此这第四个条件以及以下所有其他评估结果为 false.
用户按下键 7、6 或 5[=232 时的行为大致相同=].
用例 4: 用户按下键 4.
CHOICE.COM
退出,值4
分配给ERRORLEVEL
。- 前六个条件全部计算为false。
- 第七个条件
if errorlevel 4
是 true 因此执行命令 GOTO 导致继续批处理文件处理带有标签menu3
的行下方的行。因此其他 IF 条件在此用例中无关紧要。
用户按下键 3 或 2.
时的行为大致相同用例 5: 用户按下键 1.
CHOICE.COM
退出,值1
分配给ERRORLEVEL
。- 前九个条件全部评估为false。
- 最后一个条件
if errorlevel 9
为 true,因此批处理文件file1.bat
被命令处理器 调用。 COMMAND.COM
在处理完file1.bat
后继续上线,除了EXIT命令在处理file1.bat
的过程中被执行。
此代码至少存在三个潜在问题:
- 调用批处理文件的已执行命令或应用程序的最后退出代码决定了主批处理文件中的处理行为。这不是这里真正想要的。
- 如果 调用的 批处理文件中的 none 修改了
ERRORLEVEL
的值,就像只包含一系列set variable=value
, IF 条件下的 IF 条件导致调用另一个批处理文件也是 true这导致再调用一个批处理文件或继续对menu3
. 的代码进行批处理文件处理
- 最后一个条件下面的代码
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 根据 errorlevel
由 CHOICE.COM
设置。
上面的代码导致在用户按下键 Y 时执行 file6.bat
,而忽略此主批处理文件中的其余行。在子菜单 1 的适当代码上按 2、3 或 4 继续批处理文件处理, 2 or 3. 但对于键 1, 5 to 8 and 7 被 称为 适当的批处理文件,然后定义的环境变量 BatFile
未定义,批处理文件处理继续并再次打印主菜单并让用户使用多一个选择。
当然也可以将要调用的批处理文件的完整文件名分配给环境变量BatFile
,而不仅仅是它的编号,如果要调用的批处理文件具有不同的文件名并且只是文件扩展名是所有要调用的批处理文件都一样。在这种情况下,带有 CALL 的命令行将是 call %BatFile%.bat
.