为什么在提示用户输入字符串/选项不按预期工作后进行字符串比较?

时间:2017-01-02 22:25:17

标签: batch-file

这是编写这些批处理代码行的正确方法,除了空格和不需要的百分号之外?

<section>

批量用户输入后播放器名称不会输出。

:name cls echo now that we've got your color figured out, what about your name? echo simply type the name you want for your character into the space below echo (6 char max) echo. set /p %player% = cls echo so you want your name to be %player% ? echo. echo 1) yes echo 2) no set /p %namechoice% = if %namechoice% == 1 goto check if %namechoice% == 2 goto name :check if /I %player% == %username% (goto gamestart) else goto suprise :suprise check的字符串比较也无效。

命令行name导致批处理文件执行中断,并显示错误消息:

  

goto此时出乎意料。

1 个答案:

答案 0 :(得分:1)

主要错误是一个简单的语法问题:

定义环境变量时只指定不带百分号的变量名称,并且在等号前没有空格字符。

错误的是

set /p %player% =
set /p %namechoice% =

因为这两行在预处理阶段被扩展,然后才真正执行命令 SET

set /p  =
set /p  =

如果尚未定义环境变量playernamechoice。有关如何正确定义环境变量的详细信息,请参阅Why is no string output with 'echo %var%' after using 'set var = text' on command line?。它还解释了为什么在变量定义上留下等号的空格字符成为变量名的一部分,这几乎总是不受批处理文件编写者的影响。

在批处理文件的顶部运行批处理文件没有 @echo off或将此行修改为@echo on或注释掉时,可以很容易地看到这种简单的语法问题通过在双引号中输入带有完整路径的批处理文件的名称而不是双击批处理文件,在命令提示符窗口中输入::@echo off(无效标签)或rem @echo off(备注命令)。

有什么区别?

  1. 使用@echo off命令行在执行它们之前预处理(扩展环境变量)后,打印到控制台窗口中。批处理文件开发完成后,这是想要的行为。但是在批处理文件的开发和测试过程中,最好能够显示Windows命令解释器实际执行的内容以查找编码错误。

  2. 在双击批处理文件cmd.exe时,启动批处理文件/C,以便在批处理文件执行终止时自动关闭控制台窗口,而不依赖于成功或执行错误。这使得无法查看Windows命令解释器输出的语法错误,导致批处理文件执行立即退出。因此,建议在批处理文件开发期间从手动打开的命令提示符窗口中运行它,因为在这种情况下,cmd.exe以选项/K启动,以便在批处理完成后保持控制台窗口打开,除非批处理文件使用不带参数exit的命令/B。这样就可以看到导致意外退出批处理的错误的错误消息。

  3. 稍后当批处理文件按预期工作时,第一行可以再次@echo off,当然可以通过双击启动批处理文件。但是在批处理文件开发期间,始终最好在命令提示符窗口中运行批处理文件。向上/向下箭头键可用于滚动输入的字符串列表,这样也可以轻松地重新输入例如播放器名称。

    以下是使用多项改进和注释重写的批处理代码:

    @echo off
    setlocal EnableExtensions EnableDelayedExpansion
    
    rem Define a too long player name before prompting the user for the player
    rem name. This too long player name is kept in case of user hits just the
    rem key RETURN or ENTER without entering anything at all. Then test for
    rem entered name has not more than 6 characters. Delayed expansion is used
    rem as the user could enter characters like " ! % ... which would in further
    rem batch code execution result in exiting batch processing because of syntax
    rem error or in unexpected behavior on referencing player name with expansion
    rem before running the command.
    
    :PromptForName
    cls
    echo Now that we've got your color figured out, what about your name?
    echo Simply type the name you want for your character into the space
    echo below (6 char max).
    echo/
    set "Player=No name entered"
    set /P "Player=Player name: "
    if not "!Player:~6!" == "" goto PromptForName
    
    echo/
    echo/
    echo    1) yes
    echo    2) no
    echo/
    choice /C:12 /N "So you want your name to be !player!? "
    if errorlevel 2 goto PromptForName
    
    if /I "!player!" == "%USERNAME%" goto GameStart
    
    echo Surprise
    endlocal
    goto :EOF
    
    :GameStart
    echo/
    echo Okay !Player!, let's play^^!
    
    rem Wait 3 seconds using PING instead of TIMEOUT before exiting the
    rem batch file because the command TIMEOUT does not exist on Windows XP.
    %SystemRoot%\System32\ping.exe 127.0.0.1 -n 4 >nul
    
    endlocal
    

    顶部的评论解释了为什么环境变量Player定义为值No name entered。批处理用户可以自由点击 RETURN ENTER 而不输入任何内容,或者在输入名称之前错误地点击其中一个键。在这种情况下,如果之前未定义,则环境变量Player仍未定义,或者如果之前已定义,则保留其当前值。如果用户没有输入任何内容并且在这种情况下未定义环境变量Player,那就不好了。因此,播放器名称预定义为无效名称。

    输入的玩家名称的长度也会在太长时间内进行测试。

    用户输入的字符串可能包含批处理语法关键字符,如双引号,百分号,重定向操作符(尖括号,管道),符号,或延迟扩展启用感叹号。为防止在命令行执行之前使用环境变量扩展通过输入的播放器名称导致语法错误导致批处理退出,在批处理文件顶部启用延迟扩展使用环境变量Player

    要打印空白行,最好使用echo/而不是echo.,因为echo.可能会失败并且因为Windows命令解释程序搜索匹配的文件而稍微慢一点模式echo.*,如DosTips论坛文章ECHO. FAILS to give text or blank line - Instead use ECHO/中所述。

    如果用户必须输入特定密钥,则命令 CHOICE set /P VariableName=Prompt text好得多。命令 CHOICE 不允许用户输入批处理文件编写器不需要的内容,因此对选择菜单更安全。

    使用%USERNAME%引用的当前用户的帐户名称也可以包含空格字符。因此,强烈建议将包含%USERNAME%的整个字符串始终用双引号括起来。

    字符串比较右侧的

    "%USERNAME%"要求左侧的字符串也用双引号括起来,因为命令 IF 会比较两个字符串并包含双引号。

    由于这个原因,条件

    if /I !player! == "%USERNAME%"
    

    仅当批处理文件用户输入带双引号的播放器名称时才会出现,这是非常不可能的。双引号也必须在左侧使用。

    用双引号括起来或未用双引号括起来的两个比较字符串周围的空格字符数无关紧要。

    在命令提示符窗口中执行以下批处理文件

    @echo on
    @setlocal EnableExtensions EnableDelayedExpansion
    @set "Player=<|>"
    if /I "!Player!"=="%SystemRoot%" echo Strings are equal.
    if /I "!Player!"  ==  "%WinDir%" echo Strings are equal.
    if /I   "!Player!" ==  "%Player%" echo Strings are equal.
    if /I "!Player!"==   "!Player!" echo Strings are equal.
    if   /I   !Player!  ==  !Player! echo Strings are equal.
    @endlocal
    

    导致输出

    if /I "!Player!" == "C:\WINDOWS" echo Strings are equal.
    
    if /I "!Player!" == "C:\WINDOWS" echo Strings are equal.
    
    if /I "!Player!" == "<|>" echo Strings are equal.
    Strings are equal.
    
    if /I "!Player!" == "!Player!" echo Strings are equal.
    Strings are equal.
    
    if /I !Player! == !Player! echo Strings are equal.
    Strings are equal.
    

    可以看出,执行命令 IF 时,比较运算符==周围的空格字符无关紧要。 Windows命令处理器在执行 IF 命令之前格式化命令行。

    但要比较的字符串中的空格字符需要使用双引号,否则批处理的退出很可能是因为批处理文件执行时出现语法错误。

    注意:命令 IF 的等于运算符==的处理方式与命令 SET 的赋值运算符=不同STRONG>。不要混合它们。

    要了解使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面。

    • choice /?
    • cls /?
    • echo /?
    • endlocal /?
    • goto /?
    • if /?
    • ping /?
    • rem /?
    • set /?
    • setlocal /?

    另请参阅Microsoft文章Using command redirection operators以获取>nul的解释。