Batch file 如何阻止Windows命令解释器在用户输入错误时退出批处理文件执行?

Batch file 如何阻止Windows命令解释器在用户输入错误时退出批处理文件执行?,batch-file,Batch File,如果我有以下示例代码: @echo off :menu cls echo 1. win echo 2. lose set /p menu= goto %menu% pause>nul :win cls echo yay lolz pause>nul :lose cls echo really? pause>nul 如果键入“test”而不是有效响应,如何阻止批退出?首先,我建议在浏览器中添加书签: (SS64) 您可以通过在命令提示符窗口中运行带有/?作为参数的命令

如果我有以下示例代码:

@echo off
:menu
cls
echo 1. win
echo 2. lose
set /p menu=
goto %menu%
pause>nul

:win
cls
echo yay lolz
pause>nul

:lose
cls
echo really?
pause>nul

如果键入“test”而不是有效响应,如何阻止批退出?

首先,我建议在浏览器中添加书签:

  • (SS64)
您可以通过在命令提示符窗口中运行带有
/?
作为参数的命令来获取每个Windows命令的帮助,例如
if/?
set/?


第二,如果用户应该从几个选项中选择一个,不要使用
set/p
。提示用户输入字符串并将其分配给环境变量时,必须考虑多个事实:

  • 使用
    set/p“MyVar=Your choice:“
    如果用户有意或错误地按下,则不会修改环境变量
    MyVar
    ,只要返回或输入即可。这意味着,如果在用户提示之前未定义环境变量
    MyVar
    ,则在用户提示完成后,只要按回车键,环境变量仍然未定义。如果在用户提示之前已经定义了
    MyVar
    ,它将保持其值不变,以防用户只按RETURN或ENTER

  • 用户可以自由键入任何字符串,只要提示使用
    set/p
    。批处理文件编写器无法控制用户真正输入的内容。因此,批处理文件编写器必须考虑到,用户错误地或有意地输入了一个字符串,该字符串可能由于语法错误而导致批处理文件执行的退出,或者它执行的操作与定义的完全不同

  • 一个简单的例子:

    @echo on
    :MainMenu
    @set /P "menu=Your choice: "
    if %menu% == 1 goto Label1
    if %menu% == 2 goto Label2
    goto MainMenu
    
    :Label1
    @echo Option 1 was chosen, fine.
    goto :EOF
    
    :Label2
    @echo Option 2 was chosen, okay.
    
    出于调试目的,此批处理文件在命令提示窗口中启动,顶部显示的是
    echo on
    ,而不是
    echo off

    第一次运行时,在用户提示下按Just RETURN。Windows命令解释器退出批处理,因为第一个IF条件在执行IF命令之前进行了预处理:

    if  == 1 goto Label1
    
    显然缺少了第一个论点
    cmd.exe
    遇到此语法错误,并以相应的错误消息退出批处理。原因是缺少环境变量
    菜单
    的定义,该变量在用户提示前未定义,在用户提示后仍未定义

    字符串
    2
    在从命令提示符窗口第二次运行批处理文件时输入,批处理文件按预期工作

    在同一命令提示窗口中再次运行批处理文件时,在用户提示下按RETURN键。批处理文件再次输出第二条消息。为什么?环境变量
    菜单
    仍然使用该字符串从第二批文件执行中定义,并且在按RETURN键时未修改该变量

    好的,让我们将示例批处理文件修改为:

    @echo on
    :MainMenu
    @set "menu=2"
    @set /P "menu=Your choice: "
    if "%menu%" == "1" goto Label1
    if "%menu%" == "2" goto Label2
    goto MainMenu
    
    :Label1
    @echo Option 1 was chosen, fine.
    goto :EOF
    
    :Label2
    @echo Option 2 was chosen, okay.
    
    这已经更好了,因为现在环境变量
    菜单
    总是用值
    2
    预定义的。因此,如果用户不输入任何内容,则跳转到
    Label2
    。此外,变量
    菜单的上一次运行的值对批处理文件的执行不再有影响

    但现在这真的是安全的和故障安全的吗

    不,不是。用户仍然可以错误地输入错误的字符串

    例如,用户错误地输入了
    而不是
    2
    ,这在德国键盘上很容易,因为CapsLock+2或Shift+2会导致输入
    。预处理后的第一个IF命令行现在是:

    if """ == "1" goto Label1
    
    这也是一个无效的命令行,由于语法错误导致批处理文件处理退出

    假设用户在提示符下输入字符串:

    " == "" call dir "%USERPROFILE%\Desktop" & rem 
    
    注意:末尾有一个空格

    第一个IF条件由Windows命令解释器预处理为:

    if "" == "" call dir "%USERPROFILE%\Desktop"   & rem " == "1" goto Label1
    
    可以看出,批处理文件现在在两种IF条件下都执行一个根本没有写入批处理文件的命令

    如何获得故障安全的用户提示

    通过使用延迟环境变量展开,至少在代码周围评估用户输入字符串

    @echo on
    :MainMenu
    @setlocal EnableDelayedExpansion
    @set "menu=2"
    @set "Label=MainMenu"
    @set /P "menu=Your choice: "
    if "!menu!" == "1" set "Label=Label1"
    if "!menu!" == "2" set "Label=Label2"
    endlocal & goto %Label%
    
    :Label1
    @echo Option 1 was chosen, fine.
    goto :EOF
    
    :Label2
    @echo Option 2 was chosen, okay.
    
    现在,用户输入字符串不再修改Windows命令解释器执行的命令行。因此,由于用户输入引起的语法错误而退出批处理文件处理不再可能。批处理文件从不执行批处理文件中未写入的命令


    第三,对于简单的选择菜单,有比
    set/p
    更好的命令

    用户不再有自由输入批处理文件编写器未定义的内容。用户按下1、2、e或Shift+e后,批处理文件将立即继续。除Ctrl+C外,
    选项将忽略所有其他内容

    动态变量
    ERRORLEVEL
    choice
    终止后,有三个选项,几乎总是在1到3范围内的值,返回1到3作为调用
    cmd.exe的退出代码。例外情况是罕见的使用案例,即批处理文件的用户在提示下按Ctrl+C,然后回答下一个提示
    终止批处理作业(Y/N)?
    cmd.exe
    带有N。在这种情况下,动态变量
    ERRORLEVEL
    的值为
    0
    ,这就是为什么
    如果不是ERRORLEVEL 1,则转到main menu
    来处理这个非常特殊的用例的原因

    注意:
    如果错误级别X
    表示如果大于或等于X。因此,始终需要从命令
    选项的最高可能退出代码开始

    由于分配给
    ERRORLEVEL
    的退出代码是众所周知的,因此可以在较大的菜单上使用适当的标签进一步优化代码:

    @echo off
    :MainMenu
    cls
    echo/
    echo    1 ... Option 1
    echo    2 ... Option 2
    echo    E ... Exit
    echo/
    %SystemRoot%\System32\choice.exe /C 12E /N /M "Your choice: "
    goto Label%ERRORLEVEL%
    
    :Label0
    rem The user pressed Ctrl+C and on next prompt N and
    rem so made no choice. Prompt the user once again.
    goto MainMenu
    
    :Label1
    @echo Option 1 was chosen, fine.
    goto :EOF
    
    :Label2
    @echo Option 2 was chosen, okay.
    goto :EOF
    
    :Label3
    
    命令的使用选项
    @echo off
    :MainMenu
    cls
    echo/
    echo    1 ... Option 1
    echo    2 ... Option 2
    echo    E ... Exit
    echo/
    %SystemRoot%\System32\choice.exe /C 12E /N /M "Your choice: "
    goto Label%ERRORLEVEL%
    
    :Label0
    rem The user pressed Ctrl+C and on next prompt N and
    rem so made no choice. Prompt the user once again.
    goto MainMenu
    
    :Label1
    @echo Option 1 was chosen, fine.
    goto :EOF
    
    :Label2
    @echo Option 2 was chosen, okay.
    goto :EOF
    
    :Label3