为什么提示用户输入字符串/选项后,字符串比较无法正常工作? [英] Why is string comparison after prompting user for a string/option not working as expected?

查看:75
本文介绍了为什么提示用户输入字符串/选项后,字符串比较无法正常工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

: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

批处理用户输入后,不会输出播放器名称.

checkname的字符串比较也不起作用.

命令行if %namechoice% == 1 goto check导致批处理文件执行中断,并显示错误消息:

这次,goto出乎意料.

解决方案

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

仅通过指定变量名称(不带百分号且等号前没有空格字符)来定义环境变量.

那是错的

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

因为在实际执行命令 SET

之前,在预处理阶段会扩展这两行

set /p  =
set /p  =

在尚未定义环境变量playernamechoice的情况下,

.请参阅为什么在命令行上使用'set var = text'后,为什么没有'echo%var%'的字符串输出?有关如何定义环境变量的详细信息.它也解释了为什么在变量定义上留给等号的空格字符成为变量名的一部分,而批处理文件编写器几乎总是不希望使用该空格符.

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

有什么区别?

  1. 使用@echo off命令行(在实际执行之前,在预处理(扩展环境变量)之后)不会打印到控制台窗口中.批处理文件开发完成时,这是所需的行为.但是在开发和测试批处理文件的过程中,最好显示Windows命令解释器实际执行的操作以发现编码错误.

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

稍后,当批处理文件按预期方式工作时,第一行可以再次为@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

顶部的注释说明了为什么使用值No name entered定义环境变量Player的原因.批处理用户可以自由点击 RETURN ENTER 而无需输入任何内容,也可以在输入名称之前误击这两个键之一.在这种情况下,如果尚未定义环境变量Player,则该变量要么仍未定义,要么如果之前已定义,则保持其当前值.如果用户不输入任何内容并且在这种情况下未定义环境变量Player,那是不好的.因此,玩家名称是用无效的名称预定义的.

输入的玩家名称的长度也会过长进行测试.

用户输入的字符串可以包含批处理语法关键字符,例如双引号,百分号,重定向运算符(尖括号,竖线),&"号,或在延迟扩展后启用感叹号.为了防止由于在命令行执行前使用环境变量扩展名而输入的播放器名称引起的语法错误而导致退出批处理过程,在各处都引用了环境变量Player,并在批处理文件的顶部启用了延迟扩展.

对于打印空白行,最好使用echo/而不是echo.,因为echo.可能会失败,并且由于Windows命令解释程序会搜索与模式echo.*相匹配的文件而导致速度变慢在DosTips论坛文章 ECHO中.未能输入文本或空白行-而是使用ECHO/.

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

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

字符串比较右侧的

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

因此,条件

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

仅当批处理文件用户使用双引号输入播放器名称(这是极不可能的)时,才为true.双引号也必须在左侧使用.

用双引号引起来的两个比较字符串周围的空格字符的数量无关紧要.

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

@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 的赋值运算符=不同.不要混在一起.

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面.

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

另请参见Microsoft文章使用命令重定向运算符 >nul的说明.

Is this the proper way to write these lines of batch code with the exceptions of spaces and unneeded percent signs?

: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

The player name is not output after batch user entered it.

And the string comparisons with check and name are also not working.

The command line if %namechoice% == 1 goto check results in break of batch file execution with error message:

goto was unexpected at this time.

解决方案

The main mistake is a simple syntax issue:

Environment variables are defined with just specifying the variable name without percent signs and with no space character before the equal sign.

So wrong is

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

because those two lines are expanded during preprocessing phase before really executing the command SET to

set /p  =
set /p  =

in case of environment variables player and namechoice are not already defined. See Why is no string output with 'echo %var%' after using 'set var = text' on command line? for details about how to define an environment variable right. It explains also why the space character left to equal sign on variable definition becomes part of the variable name which is nearly always unwanted by batch file writer.

Such simple syntax issues can be easily seen on running a batch file without @echo off at top of the batch file or with this line modified to @echo on or commented out with ::@echo off (invalid label) or rem @echo off (remark command) from within a command prompt window by entering name of the batch file with full path in double quotes instead of double clicking on the batch file.

What makes the difference?

  1. With @echo off the command lines are not printed into the console window after preprocessing (expanding environment variables) before really executing them. This is the wanted behavior when batch file development finished. But during development and testing of a batch file it is definitely better to get displayed what is really executed by Windows command interpreter to find coding mistakes.

  2. On double clicking a batch file cmd.exe is started to execute the batch file with option /C for closing the console window automatically when batch file execution terminated independent on success or error of execution. This makes it not possible to see for example syntax errors output by Windows command interpreter which result in an immediate exit of batch file execution. Therefore it is advisable during batch file development to run it from within a manually opened command prompt window as in this case cmd.exe is started with option /K to keep the console window open even after batch processing finished, except the batch file uses command exit without parameter /B. This makes it possible to see also the error message of an error which caused an unexpected exit of batch processing.

Later when batch file works as expected, the first line can be @echo off again and of course the batch file can be started with a double click. But during batch file development it is definitely better to always run the batch file from within a command prompt window. The up/down arrow keys can be used to scroll through the list of entered strings which makes it also possible to re-enter for example the player name easily again.

Here is the batch code rewritten with several improvements and comments:

@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

The comment at top explains why the environment variable Player is defined with value No name entered. The batch user has the freedom to hit just RETURN or ENTER without entering anything at all or hits by mistake one of those 2 keys before entering a name. In this case the environment variable Player is either still not defined if not defined before, or it keeps its current value if already defined before. It is not good if the user enters nothing and the environment variable Player is not defined in this case. Therefore the player name is predefined with an invalid name.

The length of the entered player name is also tested on being too long.

And the string entered by the user could contain batch syntax critical characters like a double quote, a percent sign, a redirection operator character (angle bracket, pipe), an ampersand, or with delayed expansion enabled an exclamation mark. To prevent an exit of batch processing caused by a syntax error by entered player name on using environment variable expansion before command line execution, the environment variable Player is referenced everywhere with usage of delayed expansion enabled at top of the batch file.

For printing a blank line it is better to use echo/ instead of echo. because echo. could fail and is a little bit slower because of Windows command interpreter searches for a file matching the pattern echo.* as documented in DosTips forum article ECHO. FAILS to give text or blank line - Instead use ECHO/.

The command CHOICE is much better than set /P VariableName=Prompt text if the user has to enter specific keys. The command CHOICE does not allow that the user enters something not wanted by batch file writer and is therefore much safer for a choice menu.

The account name of current user referenced with %USERNAME% could contain also a space character. Therefore it is highly recommended to enclose the entire string containing %USERNAME% always in double quotes.

"%USERNAME%" on right side of a string comparison requires that the string on left side is also enclosed in double quotes because command IF compares the two strings with including the double quotes.

For that reason the condition

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

would be only true if the batch file user would have entered the player name with double quotes which is very unlikely. The double quotes must be also used on left side.

The number of space characters around the two compared strings enclosed in double quotes or not enclosed in double quotes does not matter.

Executing in a command prompt window the following batch file

@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

results in the output

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.

It can be seen that the space characters around comparison operator == do not matter on execution of command IF. The Windows command processor formats the command lines pretty before executing the IF commands.

But a space character in a string to compare requires the usage of double quotes because otherwise an exit of batch processing occurs most likely because of a syntax error on batch file execution.

Note: The equal operator == of command IF is handled different than the assignment operator = of command SET. Don't mix them.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

And see also the Microsoft article Using command redirection operators for an explanation of >nul.

这篇关于为什么提示用户输入字符串/选项后,字符串比较无法正常工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆