My companion answer to jeb's answer to "How does the Windows Command Interpreter (CMD.EXE) parse scripts?" does explain the behavior.
My companion answer gives the necessary details on how % expansion works to fully predict the behavior.
If you keep ECHO ON, then you can see the result of the expansion, and the error message makes sense:
test.bat
@echo on
@set "ARGV="
if "%ARGV:~,1%"==":" echo %ARGV% begins with a colon.
-- output --
C:\test>test
echo was unexpected at this time.
C:\test>if "~,1" echo begins with a colon.
The important rules from my answer that explain the expansion result are:
1)(Percent) Starting from left, scan each character for %
. If found then
- 1.1 (escape
%
) ... not relevant
- 1.2 (expand argument) ... not relevant
- 1.3 (expand variable)
- Else if command extensions are disabled then ... not relevant
- Else if command extensions are enabled then Look at next string of characters, breaking before
%
:
or <LF>
, and call them VAR
(may be an empty list). If VAR breaks before :
and the subsequent
character is %
then include :
as the last character in VAR and
break before %
.
- If next character is
%
then Replace %VAR%
with value of VAR (replace with nothing if VAR not defined) and continue scan
- Else if next character is
:
then
- If VAR is undefined then Remove
%VAR:
and continue scan.
- ... Remainder is not relevant
Starting with
if "%ARGV:~,1%"==":" echo %ARGV% begins with a colon.
The variable expansion expands all of the following strings to nothing because the variable is undefined:
%ARGV:
%"==":
%ARGV%
And you are left with:
if "~,1" echo begins with a colon.
It works with delayed expansion because the IF statement is parsed before delayed expansion (explained in jeb's answer within phase 2)
Everything works from the command line because the command line variable expansion does not remove the string when the variable is not defined. (loosely explained in jeb's answer near the bottom within CmdLineParser:, Phase1(Percent))