通过对环境变量的值进行区分大小写的字符串比较,可以非常简单地检查一个环境变量(如mystring
)的值与另一个环境变量(如MyStringCheck
)的值是否相等。在此之前,需要先定义MyStringCheck
并将其值设置为mystring
,并将所有双引号替换为空字符串以删除所有双引号。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "mystring=Non quoted string"
set "myquotedstring="My quoted string""
setlocal EnableDelayedExpansion
set "_StringCheck=!mystring:"=!"
if !mystring! == !_StringCheck! (
echo mystring is defined with NOT quoted string: !mystring!
) else echo mystring is defined with quoted string: !mystring!
set "mystring="!_StringCheck!""
set "_StringCheck=!myquotedstring:"=!"
if !myquotedstring! == !_StringCheck! (
echo myquotedstring is defined with NOT quoted string: !myquotedstring!
) else echo myquotedstring is defined with quoted string: !myquotedstring!
set "myquotedstring="!_StringCheck!""
rem Output the two environment variables after string checking.
echo/
echo The environment variables mystring and myquotedstring are now:
echo/
set my
endlocal
endlocal
这段代码没有必要的IF条件:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "mystring=Non quoted string"
set "myquotedstring="My quoted string""
setlocal EnableDelayedExpansion
set "mystring="!mystring:"=!""
set "myquotedstring="!myquotedstring:"=!""
echo The environment variables mystring and myquotedstring are:
echo/
set my
endlocal
endlocal
为什么要检查字符串是否带引号并添加引号?
通常最好将字符串分配给环境变量时不加引号,并在批处理文件中使用引号,当需要引用环境变量的值时进行引用,但在不需要引用时,像ECHO行一样不带引号引用环境变量值。
其他答案包含了易于检查分配给环境变量的字符串是否被括在"
中的解决方案,但它们都没有处理罕见的用例,即分配给环境变量的字符串只有一个"
,无论是在开头还是结尾,或者分配给环境变量的字符串根本只有一个字符,甚至可能是"
。
批处理文件的作者很容易控制分配给环境变量的字符串在批处理文件中的外观。但是,如果通过参数字符串将字符串传递给批处理文件或提示用户输入分配给环境变量的字符串,则必须使用附加代码使批处理文件执行失误安全,以防止错误的用户输入或参数字符串。
例如:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Example for processing an argument.
set "FirstArgument=%~1"
if defined FirstArgument set "FirstArgument=%FirstArgument:"=%"
setlocal EnableDelayedExpansion
echo First argument without quotes is: !FirstArgument!
endlocal
echo First argument with quotes is: "%FirstArgument%"
rem Example for processing a user input.
set "UserInput=""
set /P "UserInput=Please enter something: "
set "UserInput=%UserInput:"=%"
setlocal EnableDelayedExpansion
echo User input without quotes is: !UserInput!
endlocal
echo User input with quotes is: "%UserInput%"
endlocal
在这个例子中,首先通过前两个命令行完全定义了所需的执行环境,即:
- 禁用命令回显模式
- 启用命令扩展
- 禁用延迟环境变量扩展
SETLOCAL 命令不仅将命令扩展和延迟扩展的当前状态推送到堆栈上,并根据使用的两个选项启用命令扩展和禁用延迟扩展,还会复制在批处理文件启动时已定义的所有环境变量。这个新创建的环境变量列表将用于批处理文件的其余部分。 SETLOCAL 还将当前目录的路径推送到堆栈上。
批处理文件末尾的 ENDLOCAL 命令将恢复先前的执行环境,这意味着命令扩展和延迟扩展的状态将从堆栈中弹出并相应地设置。此外,创建的环境变量列表将被丢弃,并恢复初始环境变量列表,这意味着在处理完此批处理文件后,环境变量 FirstArgument
和 UserInput
将不再存在或者在批处理文件启动时已经存在,则具有其初始值。还会从堆栈中弹出当前目录路径,并在执行 ENDLOCAL 命令时重新设置该目录为当前目录(如果仍然存在)。
禁用延迟环境变量扩展,否则传递给批处理文件的参数中包含一个或多个感叹号的情况下,该演示批处理文件会处理错误。任何文件/文件夹名称都可以包含一个或多个字符!
。
处理传递给批处理文件的参数字符串
像Test.cmd
这样的批处理文件可以按以下方式启动:
Test.cmd
批处理文件在没有传递参数字符串的情况下启动,这意味着%1
被替换为空字符串。
Test.cmd C:\Temp\Example.txt
批处理文件在未用双引号括起来的参数字符串下启动。
Test.cmd "C:\Temp\ ;%Development & Test!.txt"
批处理文件在用双引号括起来的参数字符串下启动。
Test.cmd "C:\Temp\Common File Name.txt
批处理文件在参数字符串开头只有一个"
的错误情况下启动,但是参数字符串结尾缺少"
。
Test.cmd C:\Temp\FileName.txt"
批处理文件在参数字符串开头缺少"
的错误情况下启动,但是参数字符串结尾存在"
。
Test.cmd ""
批处理文件以空参数字符串启动。这通常发生在可执行文件或另一个批处理文件启动包含代码错误的批处理文件,导致批处理文件以双引号括起来的第一个参数字符串启动,但参数字符串缺失。
Test.cmd "
批处理文件仅以一个双引号字符启动。这可能发生在使用德国或英国键盘的用户想要将2
作为参数启动批处理文件,但按下了Shift+2或在按下2键时启用了CapsLock,并且用户过快地按下了RETURN或ENTER以执行命令行。
重要的是要知道,在批处理文件中无法传递包含"
并且cmd.exe
应该解释为文字字符的参数字符串。Linux shell解释器通过在参数字符串周围使用其他引号来支持此功能,但Windows cmd.exe
不支持。
在大多数批处理文件中,只使用"%~1"
,这在命令提示窗口中运行call /?
时的帮助输出中有所解释。这对于大多数用例都有效,但对于某些情况则无效,可以通过上述七个示例测试得出。
发布的批处理文件将第一个参数分配给环境变量FirstArgument
,并让cmd.exe
删除周围的双引号。
如果%~1
在此情况下被替换为空字符串,则FirstArgument
环境变量未定义为first、sixth和last示例,因此执行set "FirstArgument="
将导致删除环境变量(如果存在)。
环境变量FirstArgument
被定义为第二个、第三个和第四个示例,传递的参数字符串中没有双引号。
但是,如果参数字符串开头没有"
,则cmd.exe
在使用%~1
时不会删除参数字符串末尾的"
。因此,对于非常不寻常的第五个用例,需要额外的代码来处理这样的参数字符串,以便在不引起后续批处理文件处理退出语法错误的情况下正确处理。
第五个用例的解决方案是,如果定义了环境变量FirstArgument
,则显式地从分配给该环境变量的字符串中删除所有"
。
需要将字符串引用的字符列在帮助cmd输出中,在运行命令提示符窗口中显示的最后一个帮助页面上列出,这些字符是空格或以下字符之一&()[]{}^=;!'+,`~
。如果应将参数字符串传递到包含重定向运算符<>|
被解释为文字字符的批处理文件中,例如密码字符串,则参数字符串也必须用双引号括起来。
非常重要的是,将环境变量FirstArgument
的赋值使用命令SET的参数variable=value
时要用双引号括起来。仅使用set FirstArgument=%~1
不是安全的。为什么要使用set "variable=value"
,例如在此处中有解释。
用户在提示符上处理字符串输入
在批处理文件中使用set /P
时应该像处理参数字符串一样小心,因为用户可以输入任何内容。
- 什么都不输入或
- 输入一个包含一个或多个
"
的字符串和/或
- 输入一个包含操作符如
&<>|
的字符串。
在set /P
命令行上指定的环境变量在提示之前要么未定义,要么已经存在,如果用户只是按下RETURN或ENTER键,则仍未修改。
因此,在提示用户之前定义一个环境变量并提供有用的默认字符串,或者在set /P
命令行之后立即使用if defined variable
条件检查用户是否输入了任何内容,并相应地处理此用例,这是一个好习惯。
在演示代码中,环境变量UserInput
在提示之前以单个"
作为值进行定义。因此,如果用户没有输入任何内容,则环境变量UserInput
仍然定义为只有"
作为值。
set /P
命令行会从用户输入的字符串中去除所有的 "
。因此,在这个命令行之后,环境变量 UserInput
可能已经不存在了。在处理此类情况时,应始终考虑到这一点。最好使用通常的 if defined variable
来处理移除所有双引号后环境变量不再存在的情况。
使用 ECHO 输出环境变量字符串
将字符串分配给环境变量后,可以安全地删除包含环境变量引用的参数字符串中的所有双引号,并对其进行进一步处理,如使用环境变量引用 %variable%
本身的双引号进行括起来。
但是,有时需要输出分配给环境变量的字符串,例如文件或带路径的文件夹名称,而无需将环境变量引用括在双引号中,以便在控制台窗口或文件中使用 ECHO 命令输出。
这很棘手,因为文件/文件夹名称可能包含被 cmd.exe
解释为运算符的字符,例如 &
,或者在启用延迟环境变量扩展时被解释为环境变量引用的起始/结束符号,例如 !
。
第三个参数示例非常适合测试批处理文件,因为文件名以两个前导空格开头,接下来是一个分号和一个百分号,还包含一个“&”符号和一个感叹号。任何文件/文件夹名称都可以使用批处理文件进行处理,必须编写非常好的代码来正确处理这样的文件名。
演示代码输出参数字符串或用户输入,而不使用双引号,因此使用临时延迟环境变量扩展来避免传递给批处理文件或用户输入的字符串最终修改由cmd.exe
执行的ECHO命令行。通过测试演示批处理文件可以看到,非常不寻常的文件名C:\Temp\ ;%Development & Test!.txt
在不引起任何问题的情况下输出而不带双引号。
当然,将未知一致性的文件/文件夹名称用双引号括起来输出会更容易,因此更好。因此,每个使用ECHO打印从文件系统直接读取或作为参数传递给批处理文件或由用户在提示符上输入的包含文件/文件夹名称信息的批处理文件都应该更好地用双引号括起来。这样,用户就更容易看到文件/文件夹名称的开头和结尾,特别是如果文件/文件夹名称没有路径并且有前导空格。