如果用户只是点击 RETURN 或 ENTER 导致环境变量 password 仍然没有被定义为未使用上述行的初始值定义,则代码不起作用set /p。
这会导致 IF 条件立即扩展环境变量 password 并且在命令行中 pass 具有值 xxx:
if == xxx goto desktop
缺少左侧字符串,因此由于语法错误而退出批处理,因为从命令提示符窗口中运行批处理文件时可以看到在批处理文件顶部没有@echo off,而不是双击批处理文件。
此外,如果输入的字符串包含例如| 或& 或< 或>,则环境变量password 的立即扩展结果在解析 IF 条件行时立即退出批处理文件执行的语法错误。
将具有特殊含义的字符解释为文字字符的常见解决方案是将两个字符串放在双引号中进行比较。双引号也通过 IF 进行比较,而不仅仅是双引号之间的字符串。因此,有必要对两个字符串进行双引号。
if "%password%" == "%pass%" goto desktop
if not "%password%" == "%pass%" goto bootscreentwo
if "%password%" == "Guest" goto ltddesktop
在最后一个输出帮助页面的最后一段中,在命令提示符窗口 cmd /? 中运行,在 Windows 命令解释器输出的帮助中解释了哪些字符需要双引号引起来。此列表中缺少redirection operators>、< 和|,因为这些字符不能用于文件名。
但是,即使在字符串周围使用双引号来比较批处理文件用户是否输入包含 1 个或多个双引号的字符串时仍然存在问题,因为这会导致在执行 IF 命令行。
解决方案是使用延迟的环境变量扩展,如在命令提示符窗口 set /? 中运行时命令 SET 输出的帮助所解释。
关于用户必须输入guest 以使用访客访问的批处理代码的第一个建议:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "pass=xxx"
:EnterPassword
set "password="
set /P "password=Enter "Guest" for guest login. Password: "
if "!password!" == "" goto EnterPassword
rem Case-sensitive password string compare using delayed expansion.
if "!password!" == "!pass!" goto desktop
rem Case-insensitive password string compare using delayed expansion.
if /I "!password!" == "Guest" goto ltddesktop
echo bootscreentwo
goto :EOF
:desktop
echo Label desktop
goto :EOF
:ltddesktop
echo Label ltddesktop
goto :EOF
Windows 命令解释器在执行goto :EOF 时在退出批处理文件执行时隐式执行endlocal,从而恢复先前的命令处理环境。
以guest为默认密码的批处理代码的第二个建议:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "pass=xxx"
:EnterPassword
set "password=guest"
set /P "password=Press ENTER for guest login. Password: "
rem Case-insensitive password string compare using delayed expansion.
if /I "!password!" == "Guest" goto ltddesktop
rem Case-sensitive password string compare using delayed expansion.
if "!password!" == "!pass!" goto desktop
echo bootscreentwo
goto :EOF
:desktop
echo Label desktop
goto :EOF
:ltddesktop
echo Label ltddesktop
goto :EOF
请注意,启用延迟扩展会导致将批处理代码中的任何位置的! 解释为环境变量引用的开头。因此,例如在 ECHO 行中使用 ! 时要小心,因为感叹号必须转义才能被解释为文字字符。如果在此批处理代码块之后不再需要 password 和 pass 的值,最好在进一步处理批处理文件之前使用 endlocal。
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "pass=xxx"
:EnterPassword
set "password=guest"
set /P "password=Press ENTER for guest login. Password: "
rem Case-insensitive password string compare using delayed expansion.
if /I "!password!" == "Guest" endlocal & goto ltddesktop
rem Case-sensitive password string compare using delayed expansion.
if "!password!" == "!pass!" endlocal & goto desktop
endlocal
echo bootscreentwo with pass and password not defined anymore.
goto :EOF
:desktop
echo Label desktop with pass and password not defined anymore.
goto :EOF
:ltddesktop
echo Label ltddesktop with pass and password not defined anymore.
goto :EOF
pass 和 password 在字符串比较之后不再定义,除非这两个环境变量在第二行中执行 SETLOCAL 命令之前已经存在,在这种情况下,它们的原始值由ENDLOCAL。有关命令 SETLOCAL 和 ENDLOCAL 的详细信息,请参阅this answer。
要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
echo /?
endlocal /?
goto /?
if /?
rem /?
set /?
setlocal /?