Referring to the command line:
set VAR 2> nul && echo Yes. || echo No!!
It seems that the SPACE between nul
and &&
becomes treated as part of the variable name, so set
does not check variables whose names begin with VAR
, but instead VAR
+ SPACE, which is apparently not defined.
I created a batch file with a lot of tests, incorporating the cases from the useful comment by user 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
And this is the related console window output:
>>> 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!!
The only cases that fail are those:
set VAR > nul && echo Yes. || echo No!!
set VAR 2> nul && echo Yes. || echo No!!
When the command parser recognises and temporarily removes the redirection part (see description of phase 2 in How does the Windows Command Interpreter (CMD.EXE) parse scripts?), potential SPACEs before >
and/or after nul
are left behind, which seem to be treated as part of the variable name by set
, unless the given variable name is quoted; just one SPACE in total seems to be tolerated though.
Take also a look at the error messages Environment variable VAR not defined
with different numbers of SPACEs behind the variable name.
The set
command seems to handle its arguments in a particular way:
@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 "
The unquoted syntax seems not to follow the standard rules for tokenisation where two or more consecutive token separators like the SPACE become combined into a single one.
The big surprise to me is that even the quoted syntax tolerances one SPACE, though it ignores all SPACEs following the closing "
at least.
Even more surprising is the fact that some other text (like X
) behind a SPACE still returns no error:
@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"