"set VAR 2> nul" 后面的条件执行失败

3

使用变量名(前缀)的 set 命令 如果没有匹配的变量定义,则将 退出代码 设置为非零值。可以通过 条件执行运算符 查询退出代码:

set VAR && echo Yes. || echo No!!

如果定义了VAR(或VARiable等),则以上代码将返回Yes。,否则将返回No!!,并搭配来自set命令的错误信息Environment variable VAR not defined
然而,当我试图抑制错误消息时,无论VAR是否被定义,都会始终输出No!!
set VAR 2> nul && echo Yes. || echo No!!

无论我是在命令提示符还是批处理文件中执行命令行,结果都是相同的。

为什么插入重定向部分(2> nul)会改变运算符 &&|| 收到的退出代码呢?


2
使用括号可以改变行为 (set VAR) 2>nul &&echo Yes.|| echo No!! - 或者 - (set VAR 2>nul) &&echo Yes.|| echo No!!,同时 >nul 之间不要有空格 => set VAR 2>nul&&echo Yes.||echo No - user6811411
这是实现您想要的一般方法:If Defined VAR (Echo Yes) Else Echo No. - Compo
1
@LotPings,谢谢!看来nul&&之间的空格很重要。我刚刚发现2> nul set VAR && ... || ...也能按预期工作;似乎有一个空格被视为变量名的一部分... - aschipfl
1个回答

4

关于命令行:

set VAR 2> nul && echo Yes. || echo No!!

似乎nul&&之间的空格被视为变量名的一部分,因此set不会检查以VAR开头的变量名称,而是VAR+空格,这显然未定义。
我创建了一个包含许多测试的批处理文件,将有用的评论中的例子整合进去,该评论由用户LotPings提供。
@echo on
@rem /* Execute test cases in a sub-routine twice,
@rem    once with variable `VAR` defined and once not: */
@for %%I in ("Value" "") do @(
    set "VAR=%%~I"
    echo/& < nul set /P ="VARIABLE: "
    if defined VAR (set VAR) else echo VAR=
    call :SUB
)
@goto :EOF

:SUB
@rem // This constitutes a list of test cases:
@echo/& echo UNQUOTED (VAR):
set VAR && echo Yes. || echo No!!
set VAR> nul && echo Yes. || echo No!!
set VAR > nul && echo Yes. || echo No!!
set VAR 2> nul && echo Yes. || echo No!!
(set VAR > nul) && echo Yes. || echo No!!
(set VAR 2> nul) && echo Yes. || echo No!!
set VAR > nul&& echo Yes. || echo No!!
set VAR 2> nul&& echo Yes. || echo No!!
> nul set VAR && echo Yes. || echo No!!
2> nul set VAR && echo Yes. || echo No!!
@echo/& echo QUOTED ("VAR"):
set "VAR" && echo Yes. || echo No!!
set "VAR"> nul && echo Yes. || echo No!!
set "VAR" > nul && echo Yes. || echo No!!
set "VAR" 2> nul && echo Yes. || echo No!!
(set "VAR" > nul) && echo Yes. || echo No!!
(set "VAR" 2> nul) && echo Yes. || echo No!!
set "VAR" > nul&& echo Yes. || echo No!!
set "VAR" 2> nul&& echo Yes. || echo No!!
> nul set "VAR" && echo Yes. || echo No!!
2> nul set "VAR" && echo Yes. || echo No!!
@goto :EOF

这是相关的控制台窗口输出:

>>> test-set.bat

VARIABLE: VAR=Value

UNQUOTED (VAR):

>>> set VAR   && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> set VAR  1>nul  && echo Yes.   || echo No!!
Yes.

>>> set VAR   1>nul  && echo Yes.   || echo No!!
Environment variable VAR   not defined
No!!

>>> set VAR   2>nul  && echo Yes.   || echo No!!
No!!

>>> (set VAR  1>nul )  && echo Yes.   || echo No!!
Yes.

>>> (set VAR  2>nul )  && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> set VAR  1>nul  && echo Yes.   || echo No!!
Yes.

>>> set VAR  2>nul  && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> set VAR  1>nul  && echo Yes.   || echo No!!
Yes.

>>> set VAR  2>nul  && echo Yes.   || echo No!!
VAR=Value
Yes.

QUOTED ("VAR"):

>>> set "VAR"   && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> set "VAR"  1>nul  && echo Yes.   || echo No!!
Yes.

>>> set "VAR"   1>nul  && echo Yes.   || echo No!!
Yes.

>>> set "VAR"   2>nul  && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> (set "VAR"  1>nul )  && echo Yes.   || echo No!!
Yes.

>>> (set "VAR"  2>nul )  && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> set "VAR"  1>nul  && echo Yes.   || echo No!!
Yes.

>>> set "VAR"  2>nul  && echo Yes.   || echo No!!
VAR=Value
Yes.

>>> set "VAR"  1>nul  && echo Yes.   || echo No!!
Yes.

>>> set "VAR"  2>nul  && echo Yes.   || echo No!!
VAR=Value
Yes.

VARIABLE: VAR=

UNQUOTED (VAR):

>>> set VAR   && echo Yes.   || echo No!!
Environment variable VAR  not defined
No!!

>>> set VAR  1>nul  && echo Yes.   || echo No!!
Environment variable VAR  not defined
No!!

>>> set VAR   1>nul  && echo Yes.   || echo No!!
Environment variable VAR   not defined
No!!

>>> set VAR   2>nul  && echo Yes.   || echo No!!
No!!

>>> (set VAR  1>nul )  && echo Yes.   || echo No!!
Environment variable VAR  not defined
No!!

>>> (set VAR  2>nul )  && echo Yes.   || echo No!!
No!!

>>> set VAR  1>nul  && echo Yes.   || echo No!!
Environment variable VAR  not defined
No!!

>>> set VAR  2>nul  && echo Yes.   || echo No!!
No!!

>>> set VAR  1>nul  && echo Yes.   || echo No!!
Environment variable VAR  not defined
No!!

>>> set VAR  2>nul  && echo Yes.   || echo No!!
No!!

QUOTED ("VAR"):

>>> set "VAR"   && echo Yes.   || echo No!!
Environment variable VAR not defined
No!!

>>> set "VAR"  1>nul  && echo Yes.   || echo No!!
Environment variable VAR not defined
No!!

>>> set "VAR"   1>nul  && echo Yes.   || echo No!!
Environment variable VAR not defined
No!!

>>> set "VAR"   2>nul  && echo Yes.   || echo No!!
No!!

>>> (set "VAR"  1>nul )  && echo Yes.   || echo No!!
Environment variable VAR not defined
No!!

>>> (set "VAR"  2>nul )  && echo Yes.   || echo No!!
No!!

>>> set "VAR"  1>nul  && echo Yes.   || echo No!!
Environment variable VAR not defined
No!!

>>> set "VAR"  2>nul  && echo Yes.   || echo No!!
No!!

>>> set "VAR"  1>nul  && echo Yes.   || echo No!!
Environment variable VAR not defined
No!!

>>> set "VAR"  2>nul  && echo Yes.   || echo No!!
No!!
只有这些情况会失败:

set VAR > nul && echo Yes. || echo No!!
set VAR 2> nul && echo Yes. || echo No!!

当命令解析器识别并临时删除重定向部分(请参阅Windows命令解释器(CMD.EXE)如何解析脚本?中第2阶段的描述),在>之前和/或之后的潜在SPACEs会留下,这些空格似乎被set视为变量名的一部分,除非给定的变量名带引号;但只能容忍一个总共的SPACE
同时看看带有不同数量空格的变量名的错误消息Environment variable VAR not definedset命令似乎以一种特定的方式处理其参数。
@set "VAR=Value"
rem // No trailing spaces -- returns `VAR=Value`:
set VAR
rem // One trailing space -- returns `VAR=Value`:
set VAR 
rem // Two or more trailing spaces -- returns an ERROR!
set VAR  
rem // No trailing spaces -- returns `VAR=Value`:
set "VAR"
rem // One trailing space -- returns `VAR=Value`!?
set "VAR "
rem // Two or more trailing spaces -- returns an ERROR!
set "VAR  "

未引用的语法似乎不遵循标记化的标准规则,其中两个或更多连续的标记分隔符(如SPACE)会组合成一个单一的标记。

让我感到惊讶的是,即使是带引号的语法,也会容忍一个SPACE,尽管它至少忽略了在闭合"后面的所有SPACEs

更令人惊讶的是,在SPACE后面有一些其他文本(如X),仍然不会返回错误:

@set "VAR=Value"
rem // No spaces behind `X`, one in front -- returns `VAR=Value`!?
set VAR X
rem // No spaces behind `X`, two in front -- returns an ERROR!
set VAR  X
rem // No spaces behind `X`, one in front -- returns `VAR=Value`!?
set "VAR X"
rem // No spaces behind `X`, two in front -- returns an ERROR!
set "VAR  X"

1
你也可以使用 set "var<space>=test",然后 set VAR 2> nul && echo Yes. || echo No!! 的结果是YES。 - jeb
1
好主意,@jeb!看起来set特别处理它的参数,我刚试了一下set VAR,后面跟着一个空格,它通过了(意味着返回了VAR=Value),但是如果有多个空格,它就失败了... - aschipfl
顺便说一下,@jeb,当定义了VAR时,set VAR X(在X之前只有一个空格,在之后没有!)返回VAR=Value,非常令人惊讶... - aschipfl
1
请注意,当VAR变量存在时,“set VAR”命令不会将错误级别重置为0;它只会在变量不存在时将错误级别设置为1,除非批处理文件具有如此答案表3所述的.cmd扩展名。似乎“set VAR”命令还管理同一答案中描述的“退出代码”,因为即使该构造打印“Yes”,“set VAR && echo Yes || echo No”结构也不会更改先前设置为1或任何值的错误级别值。@jeb - Aacini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接