什么语法将检查是否定义了包含空格的变量名称?

时间:2011-11-24 09:14:43

标签: windows batch-file environment-variables

Windows用户定义的环境变量名称可以包含除=之外的任何字符。

转义它们可以包含特殊字符。一种更简单的方法是简单地将整个SET表达式括在引号内。例如:

set "A weird & "complex" variable=My value"
set A weird ^& "complex" variable=My value

上述两个表达式都给出了相同的结果。变量名称为 A weird & "complex" variable ,值为 My value

IF DEFINED构造用于测试是否定义了变量。引号不适用于此测试,名称中的特殊字符(包括引号)必须转义。

set "A&B=value"
if defined A^&B echo This works
if defined "A&B" echo This does not work

以上转义测试工作正常。引用的测试不起作用

但是如何测试是否存在包含空格的变量?

set "A B=value"
if defined A^ B echo this does not work!

看起来上面应该有效,但事实并非如此!

我正在寻找一个不涉及使用%A B%或!A B来扩展变量的答案!

4 个答案:

答案 0 :(得分:5)

有趣的问题(我喜欢这种语法基础问题)。

显然你知道如何通过延迟扩展检查它,并且FOR参数也可以。

@echo off
setlocal
set "AAA BBB=value"
set ""AAA BBB"="
set "AAA="
for %%a in ("AAA BBB") do if defined %%~a echo FOR: This works

setlocal EnableDelayedExpansion
set "varname=AAA BBB"
if defined !varname! echo Delayed: This works

if defined %varname% ( echo percent: Never comes here 
) ELSE ( echo percent: Never comes here ? )

if defined AAA^ BBB ( echo escape1: Never comes here
) ELSE ( echo escape1: fails )

set AAA=Hello
if defined AAA^ BBB ( 
   echo escape2: It only test for AAA the BBB will be "removed"
) ELSE ( echo escape2: fails )

set "space= "
if defined AAA!space!BBB echo inject space: This works

if defined "AAA BBB"  (echo Quote1: Never comes here 
) ELSE ( echo Quote1: Fails )

set ""AAA BBB"=value"
if defined "AAA BBB" echo Quote2: This works, it checks for "AAA BBB" with quotes

在我的选择中,在 escape2 示例中,解析器首先将行拆分为令牌:
<if> <defined> <AAA BBB> <echo .... 但是在的执行时,如果已定义,它会重新扫描<AAA BBB>令牌,因此它只会获得AAA
你不能注入像AAA^^^ BBB这样的第二个转义,因为它只搜索名为AAA^的变量

我没有看到没有延迟/ FOR的解决方案,因为空间的逃逸总是失败。

编辑:也可以使用SET <varname> 解决 ijprest的解决方案使用SET命令测试变量,而无需转义varname 但它也显示了在varname内部和末尾有空格的行为。

似乎遵循这些规则:
SET varname搜索以varname开头的所有变量,但首先删除varname的最后一个空格字符后的所有字符,并删除所有前导空格。
所以你不能用空格开头搜索变量(但是创建这样的varname也有点棘手)。

如果变量名用引号括起来,那么同样的行为也是有效的,但是又存在一个规则 如果至少有两个引号,请首先删除最后一个引号后的所有字符。 使用引号内的文本,并使用“space”-rule。

样品。

set    "   abc def ghi"  junk junk
*** 1. removes the junk 
set    "   abc def ghi"
*** 2. removes the quotes
set       abc def ghi
*** 3. removes all after the last space, and the trailing spaces
set abc def
*** Search all variables beginning with abc def

答案 1 :(得分:3)

我也喜欢这样的问题! :)

这是我提出的另一种可能的解决方案......使用SET本身测试存在,并使用ERRORLEVEL结果:

set "A B=foo"
set A B >nul 2>nul&& echo 1. This works
set "A B ">nul 2>nul&& echo 2. This works

set "A weird & "complex" variable=foo"
set A weird ^& "complex" variable >nul 2>nul&& echo 3. This works
set "A weird & "complex" variable ">nul 2>nul&& echo 4. This works

请注意,这仅适用于您的变量 unique ,因为没有变量名称是另一个变量名称的前缀。否则您会冒错误,因为SET的默认行为是显示以您传递的参数开头的所有变量。如果是这种情况,您可以使用findstr:

过滤结果
set "A B="
set "A B C=foo"
set "A B ">nul 2>nul&& echo 5. Failed (false positive)
set "A B "|findstr /B /L /C:"A B=" >nul||echo 6. This works (no false positive)

此外,似乎需要变量名后面的单个尾随空格。没有它,SET经常错误地解析输入。奇怪的是,如果你在“2&gt; nul”和“&amp;&amp;”之间增加一个额外的空格如果#3它停止工作(除非你删除“&gt; nul”之前的空格)...很奇怪。

答案 2 :(得分:0)

另一种方法是将其重新分配给另一个变量(一个没有空格)并测试 。见这里:

rem Prepare ONLY variable 'a b'
set "a b=123"
echo [a b]=%a b%

rem This will ouput: [a b] is defined
set var=%a b%
if defined var (
  echo [a b] is defined
) else (
  echo [a b] is not defined
)

rem This will output: [c d] is not defined
set var=%c d%
if defined var (
  echo [c d] is defined
) else (
  echo [c d] is not defined
)

答案 3 :(得分:-2)

如果需要,我可以通过将标志定义为TRUE来实现......

rem /* sample code */
set VAR_SET=
if <some condition> set VAR_SET=TRUE&set VAR=this data has spaces

rem /* test for VAR_SET using 'if defined' */
if defined VAR_SET (
  rem /* do something with the other data in the variable %VAR% */
)

rem /* clear the flag */
set VAR_SET=